三种次序的寻访路线,它是从根结点开始沿左子树深入直到最左下端时,返回进入刚刚遇到结点的右子树;在右子树中,也是先深入到它的最左下结点时返回刚遇到结点的右子树······如此深入和返回,直到从根结点的右子树返回根结点止。在这一过程中,返回结点的顺序恰与深入结点的顺序相反,先深入的后返回,正好符合栈的特点。所以可以用栈来保存遍历过程中的结点信息来实现遍历二叉树的非递归算法,并且假定栈空间足够大不会发生栈上溢以简化算法。
1.前序遍历二叉树的非递归算法:
思想:从二叉树的根结点开始,沿左子树一直深入到最左下结点时为止,在深入的过程中访问所遇到的结点,并把所遇到结点的非空右孩子进栈,当左子树结点全部处理完之后,从栈顶退出当前最近访问过结点的右孩子,再按上述过程遍历该结点的右子树;如此重复,直到栈空为止。
在下面的算法中,二叉树以二叉链表存储,用一维数组stack[MAXSIZE]作为栈来保存结点的右孩子信息,top为栈顶指针,p始终指向寻访过程中当前要处理的结点。
[cpp]
view plain
copy
- #define MAXSIZE 100
- void nrpreorder(bitree bt)//非递归前序遍历二叉树bt
- {
- bitree stack[MAXSIZE],p;//定义局部变量
- int top=0;//栈指针初始化
- p=bt;//让p指向二叉树
- do
- {
- while(p!=NULL)//当p不为空时一直深入到最左下结点
- {
- printf(“%d\n”,p->data);//访问结点,假定data域为整型
- if(p->rchild!=NULL) //如果右子树不空
- stack[++top]=p->rchild;//右孩子进栈
- p=p->lchild;//继续搜索p的左子树
- }
- if(top>0)
- p=stack[top–];//右孩子出栈赋p,准备搜索右子树
- }while(top>0);//当栈不空时继续遍历
- }
2.中序遍历二叉树的非递归算法思想:基本与前序遍历相同,只是沿左子树向下搜索的过程中先将所遇结点进栈,待遍历完左子树返回时从栈顶退出结点并访问,然后再遍历右子树。
[cpp]
view plain
copy
- #define MAXSIZE 100
- void nrinorder(bitree bt)//非递归中序遍历二叉树bt
- {
- bitree stack[MAXSIZE],p;//定义局部变量并初始化
- int top=0;
- p=bt;
- do
- {
- while(p!=NULL)//一直深入到最左下结点
- {
- stack[++top]=p;//所遇结点进栈
- p=p->lchild;//继续搜索p的左子树
- }
- if(top>0)
- {
- p=stack[top–];//出栈一个结点
- printf(“%d\n”,p->data);//访问结点
- p=p->rchild;//继续搜索右子树
- }
- }while(top>0);//当栈不空时继续遍历
- }
3.后序遍历二叉树的非递归算法
后序遍历二叉树的非递归算法要比前序和中序稍微复杂些。后序遍历中,当搜索指针指向一个结点时,不能马上访问,需要遍历先遍历左子树,所以结点需要进栈保存;当遍历完左子树返回再次搜索该结点时还不能进行访问,还需要遍历其右子树,所以结点需要再次进栈保存;即一个结点在两次进栈两次出栈之后才能访问。为了区别某一结点指针的两次出栈,需设置一标志flag同结点同时进出栈,flag定义如下:
flag={ 0, (结点第一次进出栈,不访问);
{ 1, (结点第二次进出栈,出栈后访问);
栈中数据类型可定义为指向结点的指针和flag组成的结构体类型:
typedef struct stackelem
{
bitree link;
int flag;
}stackelemtype;
其后序遍历二叉树的非递归算法描述如下:
[cpp]
view plain
copy
- #define MAXSIZE 100
- void nrpostorder(bitree bt)//非递归后序遍历二叉树bt
- {
- stackelemtype stack[MAXSIZE];//定义栈
- bitree p;//定义巡访指针
- int top=0,sign;//栈顶指针初始化
- p=bt;//巡访指针指向二叉树的根结点
- do
- {
- if(p!=NULL)
- {
- stack[++top].link=p;//结点第一次进栈
- stack[top].flag=0;//置标志为0
- p=p->lchild;//遍历左子树准备
- }
- if(top>0)
- {
- sign=stack[top].flag;//标志出栈存于sign
- p=stack[top–].link;//结点出栈存于p
- if(sign==0)//flag为0,是第一次出栈
- {
- stack[++top].link=p;//结点第二次入栈
- stack[top].flag=1;//置标志为1
- p=p->rchild;//遍历右子树准备
- }
- else//flag为1,是第二次出栈
- {
- printf(“%d\n”,p->data);//访问结点
- p=NULL;//置p为空,为下一个结点出栈做准备
- }
- }
- }while(top>0)
- }