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


    作者: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;

        
        
    }
  • 相关阅读:
    shell 知识点
    folder,source folder,package 区别
    meta viewport 理解
    一张图看懂JavaScript中数组的迭代方法:forEach、map、filter、reduce、every、some
    java 报错及解决
    Charles :mac上的手机代理
    关联本地文件夹到github项目
    tomcat 安装
    Refused to display '[url]' in a frame because it set 'X-Frame-Options' to 'Deny'.
    linux 知识点
  • 原文地址:https://www.cnblogs.com/finallyliuyu/p/2146989.html
Copyright © 2020-2023  润新知