二叉树非递归遍历的算法题
题目:已知二叉树采用二叉链表方式存放,要求对二叉树从1开始进行连续编号,要求每个结点的编号大于其左右孩子的编号,同一个结点的左右孩子中,其左孩子的编号小于其右孩子的编号,请回答采用什么次序的遍历方式实现编号并给出在二叉树中结点的数据域部分填写实现如上要求编号的非递归算法。
由题意:从小到大顺序按照“左右根”顺序,故后序遍历。
再编写后序遍历的非递归算法(参考答案):均用栈来处理,后序非递归遍历与前序和中序的非递归遍历略有不同,相对更难一些,但大致思路一样,后序非递归一定要设置访问标记,避免根节点被重复访问。
//这是参考答案,不一定好理解
typedef struct node
{
ElemType data;
int num;
struct node *lchild, *rchild;
}Bnode,*Btree;
void postOrder(Btree t)
{
//从结点1开始编号,大于其左右孩子编号,左孩子编号小于右孩子编号
typedef struct
{
Btree t;
int tag;
}node;
Btree p=t; node sn,s[]; //s为栈,容量足够大
int k=0,top=0; //k为结点编号,top为栈顶指针
while(p!=null || top>0)
{
while(p)
{
sn.t=p;
sn.tag=0;
s[++top]=sn; //保存路径
p=p->lchild; //沿左分支向下
}
while(top>0 && s[top].tag==1)
{
sn=s[top--]; //出栈
sn.t->num=++k; //左右孩子已遍历,结点赋值编号
}
if(top>0)
{
s[top].tag=1;
p=s[top].t->rchild;
}
}
}
这里为了扩展学习,按照自己的学习和理解写了一下:
//二叉树非递归遍历
struct node
{
char data; //假设是字符型
struct node *lchild, *rchild;
}Btree;
//前序遍历
void preOrderByStack(Btree root)
{
//根节点为NULL
if(root==NLLL)
{
return;
}
//初始化一个栈去保存路径
Btree stack[10]; //存储走过的结点地址,假设10个结点
int stackTop=-1;
//用一个移动指针从根节点开始往下走
Btree pMove=root;
while(stackTop!=-1 || pMove)
{
//根 左 右
while(pMove)
{
printf("%c\t",pMove->data);
stack[++stackTop]=pMove; //保存路径
pMove=pMove->lchild;
}
//pMove==NULL 左边没有路走
if(stackTop!=-1)
{
//出栈 去上一个结点 右边
pMove=stack[stackTop]; //获取栈顶元素
stackTop--;
pMove=pMove->rchild;
}
}
}
//中序遍历
void midOrderByStack(Btree root)
{
if(root==NULL)
{
return;
}
//初始化栈
Btree stack[10]; //假设10个结点
int stackTop=-1;
//左 根 右
Btree pMove=root;
while(stackTop!=-1 || pMove)
{
//找最左边,同时保存路径(入栈)
while(pMove)
{
stack[++stackTop]=pMove;
pMove=pMove->lchild;
}
//pMove==NULL 出栈,出栈前提:栈不为空
if(stackTop!=-1)
{
pMove=stack[stackTop--];
printf("%c\t",pMove->data);
pMove=pMove->rchild;
}
}
}
//后序遍历
void lastOrderByStack(Btree root)
{
if(root==NULL)
{
return;
}
Btree stack[10]; //假设10个结点
int stackTop=-1;
//左 右 根
//这里如果按上述方法,则会重复打印根结点
Btree pMove=root;
Btree pLastVisit=NULL; //访问标记
while(pMove)
{
stack[++stackTop]=pMove;
pMove=pMove->lchild;
}
while(stackTop!=-1)
{
pMove=stack[stackTop--];
//右边为空或者右边被访问了--->根节点只有当左右都访问了才能打印
if(pMove->rchild==NULL || pMove->rchild==pLastVisit)
{
printf("%c\t",pMove->data);
pLastVisit=pMove; //改变标记的位置
}
else
{
//不为NULL,用同样的方式访问右边
stack[++stackTop]=pMove;
pMove=pMove->rchild;
while(pMove)
{
stack[++stackTop]=pMove;
pMove=pMove->lchild;
}
}
}
}