二叉树非递归遍历:
#include"btree.cpp"文件链接:https://blog.csdn.net/qq_16261421/article/details/105920539
总体代码如下:
#include "btree.cpp"
//先序非递归遍历算法
void PreOrder1(BTNode *b)
{
BTNode *St[MaxSize],*p;
int top=-1;
if (b!=NULL) {
//根结点进栈
top++;
St[top]=b;
//栈不为空时循环
while (top>-1){
p=St[top];
//退栈并访问该结点
top--;
printf("%c ",p->data);
if (p->rchild!=NULL){
top++;
St[top]=p->rchild;
}
if (p->lchild!=NULL){
top++;
St[top]=p->lchild;
}
}
printf("\n");
}
}
//中序非递归遍历算法
void InOrder1(BTNode *b)
{
BTNode *St[MaxSize],*p;
int top=-1;
if (b!=NULL){
p=b;
//处理*b结点的左子树
while (top>-1 || p!=NULL){
//扫描*p的所有左结点并进栈
while (p!=NULL){
top++;
St[top]=p;
p=p->lchild;
}
//执行到此处时,栈顶元素没有左孩子或左子树均已访问过
if (top>-1){
p=St[top]; //出栈*p结点
top--;
printf("%c ",p->data);
p=p->rchild; //扫描*p的右孩子结点
}
}
printf("\n");
}
}
//后序非递归遍历算法
void PostOrder1(BTNode *b)
{
BTNode *St[MaxSize];
BTNode *p;
int flag,top=-1; //栈指针置初值
if (b!=NULL){
do{
while (b!=NULL) {
//将*b的所有左结点进栈
top++;
St[top]=b;
b=b->lchild;
}
//执行到此处时,栈顶元素没有左孩子或左子树均已访问过
p=NULL; //p指向栈顶结点的前一个已访问的结点
flag=1; //设置b的访问标记为已访问过
while (top!=-1 && flag){
b=St[top]; //取出当前的栈顶元素
if (b->rchild==p) {
printf("%c ",b->data); //访问*b结点
top--;
p=b; //p指向刚访问过的结点
}
else{
b=b->rchild; //b指向右孩子结点
flag=0; //设置未被访问的标记
}
}
} while (top!=-1);
printf("\n");
}
}
int main()
{
BTNode *b;
CreateBTNode(b,"A(B(D(,G)),C(E,F))");
printf("b:");
DispBTNode(b);
printf("\n");
printf("先序遍历序列:");
PreOrder1(b);
printf("中序遍历序列:");
InOrder1(b);
printf("后序遍历序列:");
PostOrder1(b);
return 0;
}
先序遍历非递归算法:
算法思想:
用栈来消除递归,先将根节点进栈,在栈不空时候循环:出栈p,访问*p节点,若其右孩子节点不空,将右孩子节点进入堆栈,若其左孩子节点不空,将其左孩子节点进入堆栈。算法如下:
void PreOrder1(BTNode *b)
{
BTNode *St[MaxSize],*p;
int top=-1;
if (b!=NULL) {
//根结点进栈
top++;
St[top]=b;
//栈不为空时循环
while (top>-1){
p=St[top];
//退栈并访问该结点
top--;
printf("%c ",p->data);
if (p->rchild!=NULL){
top++;
St[top]=p->rchild;
}
if (p->lchild!=NULL){
top++;
St[top]=p->lchild;
}
}
printf("\n");
}
}
中序遍历非递归算法:
算法思想:
由中序遍历的过程可知,中序序列的开始节点是一颗二叉树的最左下节点。因此,我们的基本思路是,先找到二叉树的开始节点,并且访问它,再处理右子树。
用指针指向当前要处理的节点,先扫描(并非访问)根节点的所有左节点,并且将它们一一进栈,当无左节点时,表示栈顶节点无左子树,然后出栈这个节点,并访问它,将p指向刚出栈节点的右孩子,对右子树进行同样的处理。
需要特别注意的是,当节点*p的所有左节点进栈后,这时的栈顶节点要么没有左子树,要么左子树已经被访问过,就可以访问这个栈顶节点,如此重复操作,直到栈空为止。算法如下:
//中序非递归遍历算法
void InOrder1(BTNode *b)
{
BTNode *St[MaxSize],*p;
int top=-1;
if (b!=NULL){
p=b;
//处理*b结点的左子树
while (top>-1 || p!=NULL){
//扫描*p的所有左结点并进栈
while (p!=NULL){
top++;
St[top]=p;
p=p->lchild;
}
//执行到此处时,栈顶元素没有左孩子或左子树均已访问过
if (top>-1){
p=St[top]; //出栈*p结点
top--;
printf("%c ",p->data);
p=p->rchild; //扫描*p的右孩子结点
}
}
printf("\n");
}
}
后续遍历非递归算法:
算法思路:
后续遍历中第一个访问的节点是二叉树的最左下节点。由于首先访问节点的左右子树,然后才访问节点本身,所以对于任意节点,必须直到其左右子树是否被访问过。
使用栈来保存需要返回的节点的指针,先扫描根节点的所有左孩子节点,并且一一进栈,出栈一个节点*p作为当前节点,然后扫描该节点的右子树,当一个节点的左右孩子节点均被访问后再访问该节点,如此重复,直到栈空为止。
Q:如何判断一个节点*b的右子树已经访问过?
A:如果右孩子节点已经访问过,则其右子树就已经访问过。
用p指针保存刚访问过得节点,若b->rchild==p成立,则b的左右子树均已访问,现在应该访问*b。所以栈中保存的是当前节点*b的所有祖先节点。这些祖先节点均未被访问过。
算法如下:
//后序非递归遍历算法
void PostOrder1(BTNode *b)
{
BTNode *St[MaxSize];
BTNode *p;
int flag,top=-1; //栈指针置初值
if (b!=NULL){
do{
while (b!=NULL){
//将*b的所有左结点进栈
top++;
St[top]=b;
b=b->lchild;
}
//执行到此处时,栈顶元素没有左孩子或左子树均已访问过
p=NULL; //p指向栈顶结点的前一个已访问的结点
flag=1; //设置b的访问标记为已访问过
while (top!=-1 && flag){
b=St[top]; //取出当前的栈顶元素
if (b->rchild==p) {
printf("%c ",b->data); //访问*b结点
top--;
p=b; //p指向刚访问过的结点
}
else{
b=b->rchild; //b指向右孩子结点
flag=0; //设置未被访问的标记
}
}
} while (top!=-1);
printf("\n");
}
}
后序非递归遍历算法特点:当访问某个节点时,堆栈中保存的正好是该节点的所有祖先节点,从栈顶到栈底正好是该节点的双亲 节点到根节点路径上的节点序列。