《数据结构》遍历二叉树的非递归算法的疑问。

来源:百度知道 编辑:UC知道 时间:2024/05/17 06:53:33
问题来自《数据结构》(严蔚敏、吴伟民著,C语言描述,清华大学出版社,1997年4月第1版),第6章树与二叉树,6.3遍历二叉树和线索二叉树。

遍历二叉树的非递归算法,教材的描述如下(见130页):

仿照递归算法执行过程中递归工作栈的状态变化状况可直接写出相应的非递归算法。例如,从中序遍历递归算法执行过程中递归工作栈的状态可见:(1)工作记录中包含两项,其一是递归调用的语句编号,其二是指向根结点的指针,则当栈顶记录中的指针非空时,应遍历左子树,即指向左子树根的指针进栈;(2)若栈顶记录中的指针值为空,则应退至上一层,若是从左子树返回,则应访问当前层即栈顶记录中指针所指的根结点;(3)若是从右子树返回,则表明当前曾的遍历结束,应继续退栈。从另一角度看,这意味着遍历右子树时不再需要保存当前层的根指针,可直接修改栈顶记录中的指针即可。由此可得两个中序遍历二叉树的非递归算法如下:

=============================================================

算法一:

Status InOrderTraverse(BiTree T, Status(*Visit)(TElemType e))
{
//采用二叉链表存储结构,Visit是对数据元素操作的应用函数。
//中序遍历二叉树T的非递归算法,对每个数据元素调用函数Visit。

InitStack(S);
Push(S,T); //根指针进栈

while(!StackEmpty(s))
{
while(GetTop(S,p)&&p)
Push(S,p->lchild); //向左走到尽头
Pop(S,p); //空指针退栈
if(!StackEmpty(S)) //访问结点,向右一步
{
Pop(S,p);
if(!Visit(p->data))
return ERROR;
Push(S,p->rchild);

首先敬仰一下楼主的勤奋!

我主要针对第二个算法说,我觉得上面这段话也是在讲第二个算法。其实两个算法差不太多。
1. 栈顶记录中的指针其实就是指栈顶,每次push()进去或者pop()出来的那个p。他代表的是正在访问的节点得下一个节点。比如,访问一个树t的左子树t->lchild时,栈顶就是t;访问t->lchild->lchild时,栈顶就是t->lchild。访问t->rchild时,栈顶为NULL;访问t->lchild->rchild时,栈顶为t;访问t->rchild->lchild时,栈顶也是t;访问t->rchild->rcchild时,栈顶仍为NULL。他的意义就是,在访问完了当前的子树之后,就会去访问栈顶记录的指针对应的节点的数据。
2. 关于“工作记录”那个词,我觉得还是别深究了。那段话意思是要仿照编译器把递归编译成迭代的思路来自己写迭代算法,可是实际上后面给出的算法里根本没有严格执行上述思路,写出来的算法并不是严格意义上的可以一般性替换递归的迭代算法。所以追究那个词也没意义,明白迭代遍历的算法怎么用就够了。等以后对递归有了更深刻的认识,自然就明白了。其实就是函数递归调用自身之前像中断那样保存自己的工作环境和进度。
3. (2)句并不矛盾。他说“指针为空时”和“指针指向的xxx”中间不是有句“退回上一层”么,那就表示pop(),于是原来那个在栈顶的空指针弹出去了,原来在第二位的指针现在到了栈顶。于是后面那句指的是对这个指针进行操作。