非递归、仅用一个栈、不加标记数组实现二叉树的后序遍历算法

作者:finallyly 出处:博客园(转载请注明作者和出处)

题记:最近在复习数据结构和算法。由于之前在数据结构和算法方面没有受过密集的训练。所以刚入门,有点吃力。最主要的一个问题是:看别人的,好像一看就全懂了,但是自己写又写不出来;给定一个具体的题目,即便是看懂了别人的算法,但是过些日子回过头来自己写,还是写不出来。和我一样出现上述状况的同学要注意啦,需要改变学习方式,否则则会一直在津津有味,乐此不疲,且自以为是地做着无用功。时间是有限的,何必浪费掉大好的时间和青春去做些无意义的事情呢?静下心来想一想,任何一本《数据结构与算法》的教材无非是想告诉我们有一些编程中可以使用的工具(栈、队列、链表、二叉树、图)以及针对如何使用这些工具应用举例而已。因此,我们只要领会到精神,就算学明白了数据结构,可是如何用数据结构实现算法呢?这体现的是自己的逻辑,永远没有什么范式,也不要去过度迷信别人。只要思路对头,你也可以设计出有效果的算法来。

      对于设计算法,个人总结可以分两步:第一步:用自然语言体现出自己的思路,第二步,计算机程序亲和型的伪代码;第三步:把自己的思路用程序实现。第一步到第二步的过渡是要求,你的思路是和程序逻辑相亲和的,即用程序可以实现的。下面切入正题,讲诉非递归、仅用一个栈、不加标记数组实现二叉树的后序遍历算法的思路。

 

二叉树图例如上图。

第一步:思路

思路,根据二次树的结构特点,产生了如下的思路

1. 根节点入栈

2. 如果栈非空,则获取栈顶元素

3. 如果左孩子存在,则入栈左孩子

4. 如果左孩子不存在,但是右孩子存在则入栈右孩子

5. 如果左、右孩子都不存在,那么栈顶元素出栈,并访问已经出栈的栈顶元素

5.1 如果已出栈的元素是当前栈顶元素的左孩子,那么入栈右孩子

5.2如果已出栈元素是当前栈顶元素的右孩子,那么继续出栈并且访问当前栈顶元素

 

 

第二步,计算机程序亲和伪代码

思路如何变成计算机可以执行的逻辑?

 

考虑我们注意到 (1)5.1-5.2之间存在循环逻辑;(2)5.1 与3之间有逻辑重复。对于(1)我们可以写一个while循环,对于(2)我们可以设置一个开关变量flag,用来控制当前栈顶结点的左孩子是否参与入栈活动。

C++风格的伪代码如下

  

Bool PostOrderTraverse(Bitree T)

{

InitStack(S);

Push(S,T);

flag=0;

While(!Empty(S))

{

 Bitree e;

GetTop(S,e);

if (e->lchild&&!flag)

{

Push(S,e->lchild);

}

else

{

if(e->rchild)

{

Push(S,e->rchild);

flag=0;

}

Else

{

Bitree pOldTop;

GetTop(S,pOldTop);

Pop(S);

Visit(pOldTop);

While(!Empty(S))

{

BiTree pNewTop;

GetTop(S,pNewTop);

if (pOldTop=pNewTop->lchild)

{

flag=1;

break;

}

else

{

 Pop(S);

Visit(pNewTop);

pOldTop=pNewTop;

flag=0;

}

 

}

 

}

 

 

 

}

 

}

 

第三步:代码实现
bool PostOrderTraverseByStack(BiTree T)
{
        stack
<BiTree>bitreeStack;
    bitreeStack.push(T);
    
int flag=0;
    
    
while(!bitreeStack.empty())
    {
        BiTree pTree
=bitreeStack.top();
        
if (pTree->lchild&&!flag)
        {
            bitreeStack.push(pTree
->lchild);
        }
        
else//无需插入左孩子的模式
        {
            
if (pTree->rchild)
            {
                bitreeStack.push(pTree
->rchild);
                flag
=0;
            }
            
else
            {
                
                BiTree pTopOld
=bitreeStack.top();
                bitreeStack.pop();
                cout
<<pTopOld->data<<endl;
                
while(!bitreeStack.empty())
                { 
                   
                    
if (!bitreeStack.empty())
                    {
                        BiTree pTopNew
=bitreeStack.top();
                        
if (pTopOld==pTopNew->lchild)
                        {
                            flag
=1;
                            
break;

                        }
                        
else
                        {
                            cout
<<pTopNew->data<<endl;
                            bitreeStack.pop();
                            pTopOld
=pTopNew;
                            flag
=0;


                        }


                    }
                    
else
                    {
                        
break;
                    }
                    
                }
                

            }
        }

        
    }
    
return true;
    
}

 为了便于大家验证,把二叉树建树、销树、主函数验证的代码张贴如下

#include <iostream>
#include 
<deque>
#include 
<stack>
using namespace std;
typedef 
struct BiTNode
{
    
char data;
    BiTNode 
*lchild;
    BiTNode 
*rchild;
}BiTNode,
*BiTree;

bool CreateBiTree(BiTree &T,deque<char>& charQue)
{

    
if (!charQue.empty())
    {
        
char ch=charQue.front();
        charQue.pop_front();
        
if (ch==' ')
        {
            T
=NULL;
        }
        
else
        {
            T
=new BiTNode;
            T
->data=ch;
            CreateBiTree(T
->lchild,charQue);
            CreateBiTree(T
->rchild,charQue);

        }
        
return true;
    }
    
return true;
    
}
bool PostOrderTraverse(BiTree T)
{
    
if (T)
    {
        
if (PostOrderTraverse(T->lchild))
        {
            
if (PostOrderTraverse(T->rchild))
            {
                cout
<<T->data<<endl;
                
return true;
            }
        }
        
return false;
    }
    
else
    {
        
return true;
    }
}
bool DestroyTree(BiTree &T)
{
    
if (T!=NULL)
    {
        
if (DestroyTree(T->lchild))
        {
            
if (DestroyTree(T->rchild))
            {
                delete T;
                
return true;
            }
            

        }
        
return false;
        

    }
    
else
    {
        
return true;
    }


}
int main()
{
   BiTree root;
   deque
<char> charQue;
   charQue.push_back(
'A');
   charQue.push_back(
'B');
   charQue.push_back(
'C');
   charQue.push_back(
' ');
   charQue.push_back(
' ');
   charQue.push_back(
'D');
   charQue.push_back(
'E');
   charQue.push_back(
' ');
   charQue.push_back(
'G');
   charQue.push_back(
' ');
   charQue.push_back(
' ');
   charQue.push_back(
'F');
   charQue.push_back(
' ');
   charQue.push_back(
' ');
   charQue.push_back(
' ');
   CreateBiTree(root,charQue);
PostOrderTraverse(root);
   cout
<<"后序遍历结束"<<endl;
   PostOrderTraverseByStack(root);
   cout
<<"借助于栈的后序遍历结束"<<endl;
   DestroyTree(root);
   cout
<<"删除树完毕"<<endl;
   cout
<<"finish"<<endl;
   
int f;
   cin
>>f;
   
return 0;

    
    
}
原文地址:https://www.cnblogs.com/finallyliuyu/p/2146989.html