![5b48c5aebc514258d431aea54d47f154.gif](https://i-blog.csdnimg.cn/blog_migrate/8cf56b1722a82e3862c641dbc0870a79.gif)
“ 不用递归,二叉树怎么遍历?”
我们知道,二叉树,总共有四种遍历方法: 先序遍历, 中序遍历, 后序遍历, 层次遍历。在前面我们有讲到这四种遍历方法的递归方式实现,
什么?没讲?
看这里:【数据结构-13】二叉树的遍历
害,末尾也给了链接,可以翻到后面看噢。
那么,非递归算法是咋写的?
老规矩,我们需要先定义好树的基本结构,
这里我们用一个链表来存储树。
方法呢,就是用的C语言的结构体。
关于结构体,可以看这里:【数据结构+C语言-7】当C语言遇上数据结构
#define MaxSize 100typedef char ElemType;typedef struct node { ElemType data; //数据元素 struct node *lchild; //指向左孩子节点 struct node *rchild; //指向右孩子节点} BTNode;
定义好了树,我们就要开始遍历了。
且!!!慢!!!
先来一段大升格!
哦不好意思,走错片场了。
遍历嘛,而且这次又用的是非递归方式,那首先我们就要搞啥?
对,要完成递归算法到非递归算法的转变,
重要的就是工具人!
在数据结构里面,有两个非常著名的工具人,
一个老哥,叫做栈,
另一个老哥,叫做队列。
我们先来定义一个栈。
typedef struct { BTNode *data[MaxSize]; //存放栈中的数据元素 int top; //存放栈顶指针,即栈顶元素在data数组中的下标} SqStack;
既然有了栈,那肯定要有栈的各种操作对吧,
初始化一个栈:
void InitStack(SqStack *&s) //初始化栈{ //分配一个是顺序栈空间,首地址存放在s中 s=(SqStack *)malloc(sizeof(SqStack)); s->top=-1; //栈顶指针置为-1}
销毁一个栈:
void DestroyStack(SqStack *&s) //销毁栈{ free(s);}
判断栈空:
bool StackEmpty(SqStack *s) //判断栈是否为空{ return(s->top==-1);}
元素入栈:
bool Push(SqStack *&s,BTNode *e) //进栈{ if (s->top==MaxSize-1) //栈满的情况,即栈上溢出 return false; s->top++; //栈顶指针增1 s->data[s->top]=e; //元素e放在栈顶指针处 return true;}
元素出栈:
bool Pop(SqStack *&s,BTNode *&e) //出栈{ if (s->top==-1) //栈为空的情况,即栈下溢出 return false; e=s->data[s->top]; //取栈顶指针元素的元素 s->top--; //栈顶指针减1 return true;}
取栈顶元素:
bool GetTop(SqStack *s,BTNode *&e) //取栈顶元素{ if (s->top==-1) //栈为空的情况,即栈下溢出 return false; e=s->data[s->top]; //取栈顶元素 return true;}
到这里,
我们的工具人就差不多安排好了,
可以开始搞遍历了。
开搞!
先来一段先序遍历:
void PreOrder(BTNode *b) //先序非递归遍历算法{ BTNode *p; SqStack *st; //定义一个顺序栈指针st InitStack(st); //初始化栈st Push(st,b); //根节点进栈 while (!StackEmpty(st)) //栈不为空时循环 { Pop(st,p); //退栈节点p并访问它 printf("%c ",p->data); //访问节点p if (p->rchild!=NULL) //有右孩子时将其进栈 Push(st,p->rchild); if (p->lchild!=NULL) //有左孩子时将其进栈 Push(st,p->lchild); } printf("\n"); DestroyStack(st); //销毁栈}
再来一段中序遍历:
void InOrder(BTNode *b) //中序非递归遍历算法{ BTNode *p; SqStack *st; //定义一个顺序栈指针st InitStack(st); //初始化栈st if (b!=NULL) { p=b; while (!StackEmpty(st) || p!=NULL) { while (p!=NULL) //扫描节点p的所有左下节点并进栈 { Push(st,p); //节点p进栈 p=p->lchild; //移动到左孩子 } if (!StackEmpty(st)) //若栈不空 { Pop(st,p); //出栈节点p printf("%c ",p->data); //访问节点p p=p->rchild; //转向处理其右子树 } } printf("\n"); } DestroyStack(st); //销毁栈}
最后来一段后序遍历:
void PostOrder(BTNode *b) //后序非递归遍历算法{ BTNode *p,*r; bool flag; SqStack *st; //定义一个顺序栈指针st InitStack(st); //初始化栈st p=b; do { while (p!=NULL) //扫描节点p的所有左下节点并进栈 { Push(st,p); //节点p进栈 p=p->lchild; //移动到左孩子 } r=NULL; //r指向刚刚访问的节点,初始时为空 flag=true; //flag为真表示正在处理栈顶节点 while (!StackEmpty(st) && flag) { GetTop(st,p); //取出当前的栈顶节点p if (p->rchild==r) //若节点p的右孩子为空或者为刚刚访问过的节点 { printf("%c ",p->data); //访问节点p Pop(st,p); r=p; //r指向刚访问过的节点 } else { p=p->rchild; //转向处理其右子树 flag=false; //表示当前不是处理栈顶节点 } } } while (!StackEmpty(st)); //栈不空循环 printf("\n"); DestroyStack(st); //销毁栈}
这三个里面,后序遍历是最麻烦的,因为我们需要去记录我之前访问了哪个节点,来作为额外的判断条件。
完事。
往期回顾:
【数据结构+C语言-7】当C语言遇上数据结构
【数据结构+C语言-8】磨 刀 霍 霍
【数据结构+C语言-9】怎么操作一个链表?
【数据结构-13】二叉树的遍历
如果觉得有用,不点个再看么少年?↓
[]~( ̄▽ ̄)~*