众多周知,对于二叉树的遍历, 一种比较容易理解以及编写的方式就是递归的方式了,下面针对二叉树遍历的中序遍历做一个简单的分析:
void travelTree(BiTree T, int deep){ if (T->lchild != NULL) travelTree(T->lchild, ++deep); for (int x = 0; x < deep; x++) { printf("--"); } printf("%c ", T->data); if (T->rchild != NULL) travelTree(T->rchild, deep); }
俺们也知道,递归算法的思想有其值的我们学习之处,但是,不过否认,递归的代价也是蛮高的,这得从递归的原理来分析,这里做一下简单的叙述:
大家都知道递归的实现是通过调用函数本身,函数调用的时候,每次调用时要做地址保存,参数传递等,这是通过一个递归工作栈实现的。具体是每次调用函数本身要保存的内容包括:局部变量、形参、调用函数地址、返回值。那么,如果递归调用N次,就要分配N*局部变量、N*形参、N*调用函数地址、N*返回值。这势必是影响效率的。
那么,作为递归的一种替代方式,栈的实现,就成为了一种不错的选择:下面我就简单的叙述一下,如何在实现二叉树的遍历中来运用栈的思想:
其实嘛,说到底,递归的底层(系统级)实现也是使用栈的,如上所说,故递归的栈替换依旧不足为奇了,栈是一种先进后出结构的容器,通过简单的数据结构(j结构体),我们即可以模拟栈的实现,当然,本文主要是谈二叉树的遍历,至于栈的实现吗,读者自己去查吗!!!
同样,我们采用中序遍历类举例:
先敬上代码:
voidt InOrderTraverse(BiTree T, int(*Visit)(TElemType e)){ InitStake(S); Push(S, T); while (!StackEmpty(S)) { while (GetTop(S,P)&&p) Push(S, p->lchild); Pop(S, p); //空指针null退栈 有左孩子时,在沿着左孩子方向遍历的时候,会把一个 //null push进栈没左孩子的时候,上一次循环就必定会push进一个null 两种情况互斥 if (!StackEmpty(S)) { Pop(S, p); if (!Visit(p->data)) { return error; } Push(S, p->rchild); } } }
我们一一个简单的二叉树为例:
下面是栈操作过程:
其操作步骤可以简介为如下:
1:沿着p左孩子方向深度遍历值没有左孩子的节并按循序入栈。(前提:有左孩子) 最对会带一个空指针
去栈顶的空指针(此时栈顶绝对有一个空指针)
2:操作栈顶节点节点(访问)
3:p指向此节点的右节点(不询问) 即可能为空
重复。