三种遍历的非递归实现思路
1.前序遍历的非递归实现
首先根结点入栈,然后执行循环条件为(top!=-1)的循环,依次出栈栈中元素,每出栈一个元素需要判断其右孩子和左孩子是否存在(先右后左,因为栈是“先进后出”,而前序遍历是根左右的顺序,先访问的是左子树,所以就要让左子树后入栈以便先访问),如果存在则将其入栈,否则一直出栈直到栈空为止,代码如下:
void preorderNonrecursion(BTNode *bt)
{
if(bt)
{
BTNode* stack[maxsize],p;
int top=-1;
stack[++top]=bt;
while(top!=-1)
{
p=stack[top--];
visit(p);
if(p->rchild)//先检查右子树的原因是由于栈的"后进先出"特点,因为先序遍历是左右,所以为了确保左子树优先访问则应该让它后入栈
{
stack[++top]=p->rchild;
}
if(p->lchild)
{
stack[++top]=p->lchild;
}
}
}
}
2.后序遍历的非递归实现
后序是左右根的顺序,那么逆后序则是根右左的顺序,而前序又是根左右的顺序,那么我们可以得知,如果将前序遍历中对左右子树的检查顺序颠倒就可以得到根右左(逆后序)方式的遍历序列,看到逆我们则想到栈,如果可以以逆后序的遍历序列依次入栈在出栈则可以得到我们想要的后序遍历,代码如下:
void postorderNonrecursion(BTNode *bt)
{
if(bt)
{
BTNode*stack1[maxsize];//栈1用来辅助遍历
int top1=-1;
BTNode*stack2[maxsize];//栈2用来辅助输出最终的后序遍历序列
int top2=-1;
BTNode *p=NULL;
stack1[++top1]=bt;
while(top1!=-1)
{
p=stack1[top--];
stack2[++top2]=p;//原来的前序遍历这里是输出,现在则是将其入栈2
if(p->lchild)//15和19行顺序交换
{
stack1[++top1]=p->lchild;
}
if(p->rchild)
{
stack1[++top1]=p->rchild;
}
}
while(top2!=-1)//此时从栈顶依次输出的序列则为后序遍历序列
{
visit[stack[top2--]];
}
}
}
3.中序遍历的非递归实现
- 首先将根结点入栈,然后依次顺其左子树将其左孩子全部入栈,直到遇到某一节点无左孩子时则出栈并输出一个元素,然后判断其是否有右孩子,如果有右孩子则重复1
2.否则继续出栈一个元素,直到栈空并且刚出栈的这个元素无右孩子,代码如下:
void inorderNonrecursion(BTnode *bt)
{
if(bt!=NULL)
{
BTbode *stack[maxsize];
int top=-1;
BTnode *p=bt;//若无此语句而直接用bt来遍历会导致最终bt指向空,但其实如果不用return返回bt的话也不会有大影响(实参指向不变)
while(top!=-1||p)//top这个条件其实就是为了保证如果刚出栈的结点无右子树时好继续出栈元素准备的,p这个条件则是为了刚出栈的这个元素如果有右子树则对其右子树完全执行刚开始的最外层while循环而准备的
{
while(p)
{
stack[++top]=p;
p=p->lchild;
}
if(top!=-1)
{
p=stack[top--];
visit(p);
p=p->rchild;//p如果为NULL则下一步执行继续出栈
//p如果不为空则下一步执行入栈根结点和所有左子树结点
}
}
}
}
//该算法的执行流程是:
//1.将根结点先入栈➡️相继入栈所有左孩子节点,直到某一棵树无左子树,则出栈并输出,然后检查其
//右子树,如果存在右子树则重复1,否则继续出栈,直到栈空并且无右子树。