讨论3.4 如何用堆栈实现后序遍历的非递归程序(来源与慕课陈越姥姥的《数据结构》)
参考要点:
(1) 借助堆栈实现前序遍历、中序遍历非递归程序的本质是利用堆栈模拟递归函数调用时的入栈和出栈过程。而前序遍历、中序遍历和后序遍历在递归函数执行时,结点(作为函数参数)的入栈和出栈过程是完全一样的。
(2) 前序遍历是在结点入栈时输出结点信息,然后开始分别对该结点左右子树的遍历;而在中序遍历中,结点出栈时表明刚完成对该结点左子树的遍历,此时可输出该结点信息。
(3) 后序遍历必须在左右子树均输出的情况下才能输出该结点。如果直接采用前序遍历、中序遍历的非递归程序,我们没法判别该结点的右子树什么时候遍历结束。为了能知道结点右子树什么时候遍历结束,可以在其左子树遍历结束(即该结点出栈)时,将该结点再次入栈,等到它再次出栈时就说明其右子树刚刚遍历完毕,此时可以输出该结点。
(4) 也就是在后序遍历的非递归过程中,可以让每个结点两次入出栈,第一次出栈说明其左子树已遍历完成,第二次出栈说明右子树也遍历完成,可以输出结点信息。为了区分到底是第几次入出栈,可以给每个入栈结点增加一个标记(也就需要采用结构,其中一个分量作为标记以区分第几次入出栈)。
//堆栈实现树的非递归遍历
void No_recInorder(BinTree BT)
{
Stack S=CreatStack();
while(T||IsEmpty(S)){
while(T){
Push(S,T);
T=T->Left;
}
if(!IsEmpty(S)){
T=Pop(S);
if(Tag==0){//Tag=1,表明对应结点已经出栈了一次
Push(S,T);
Tag++;
}
else printf("%d ",T->Data);
T=T->Right;
}
}
}
讨论3.5 将层序遍历中的队列改为堆栈(来源与慕课陈越姥姥的《数据结构》)
参考要点:
(1) 层序遍历与其他三种(前序、中序和后序遍历)的主要区别是:层次遍历通过各结点一次性获得其左右儿子结点信息并借助队列以自顶向下的顺序,形成按宽度优先方式遍历二叉树。而其他三种遍历均是各结点借助堆栈的逆序特点,按自底向上的顺序逐步处理左右儿子,形成按深度优先方式遍历二叉树。
(2) 如果将层序遍历程序中的队列直接改为堆栈,同时将入栈(原来是入队)顺序改为先右儿子再左儿子,其遍历输出结果就是前序遍历。
(3) 对于中序遍历和后序遍历,关键是要判别左子树和右子树什么时候遍历结束。如果将层序遍历程序中的队列改为堆栈,同时仍然按照层次遍历的整体控制思路,对出入栈操作做些修改,仍然可以实现中序遍历和后序遍历。要点是:在原来程序控制过程中,结点出队后是将其左右儿子入队;现在可将控制过程改为:结点出栈后,将当前结点“加塞”在其左右儿子中再次入栈。如果“加塞”在左右儿子之间再次入栈就是中序遍历,如果“加塞”在左右儿子之前再次入栈就是后序遍历。也就是每个结点做两次出入栈处理(类似后序遍历的非递归程序):
1. 中序遍历要点:结点出栈时,如果是第一次出栈,按照右儿子、当前结点、左儿子顺序入栈,即左儿子在栈顶,当前结点此时是第二次入栈。将来如果第二次出栈则直接输出。
2. 后序遍历要点:过程与上述中序遍历一样,唯一区别是入栈顺序为:当前结点、右儿子、左儿子。
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
int Tag;//初始化时,Tag=0;
};
//层次遍历二叉树
void LevelorderTraversal ( BinTree BT )
{
Queue Q;
BinTree T;
if ( !BT ) return; /* 若是空树则直接返回 */
Q = CreatQueue(); /* 创建空队列Q */
AddQ( Q, BT );
while ( !IsEmpty(Q) ) {
T = DeleteQ( Q );
printf("%d ", T->Data); /* 访问取出队列的结点 */
if ( T->Left ) AddQ( Q, T->Left );
if ( T->Right ) AddQ( Q, T->Right );
}
}
void PreLevelorderTraversal ( BinTree BT )
{
Stack S;
BinTree T;
if ( !BT ) return;
S = CreatStack();
Push( S, BT );
while ( !IsEmpty(S) ) {
T = Pop(S);
printf("%d ", T->Data);
if ( T->Right ) Push( S, T->Right );
if ( T->Left ) Push( S, T->Left );
}
}
void InLevelorderTraversal ( BinTree BT )//初始默认Tag=0
{
Stack S;
BinTree T;
if ( !BT ) return;
S = CreatStack();
Push( S, BT );
while ( !IsEmpty(S) ) {//左根右->右根左,堆栈存储得反过来
T = Pop(S);
if ( T->Right ) Push( S, T->Right );
if(Tag==0){
Push(S,T);
Tag++;
}
else printf("%d ",T->Data);
if ( T->Left ) Push( S, T->Left );
}
}
void PostLevelorderTraversal(BinTree BT)//初始默认Tag=0
{
Stack S;
BinTree T;
if ( !BT ) return;
S = CreatStack();
Push( S, BT );
while ( !IsEmpty(S) ) {
T = Pop(S);
if(Tag==0){
Push(S,T);
Tag++;
}
else printf("%d ",T->Data);
if ( T->Right ) Push( S, T->Right );
if ( T->Left ) Push( S, T->Left );
}
}