【数据结构·树】二叉树:中/前/后 序遍历非递归实现(附:RE的3个原因)C++

附:RE的3个原因(见代码注释中所有加粗部分)

问题描述

目的:使用C++模板设计二叉树的抽象数据类型(ADT)。并在此基础上,使用二叉树ADT的基本操作,设计并实现简单应用的算法设计。

内容:(1)请参照链表的ADT模板,设计二叉树的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考教材、课件,以及网盘中的链表ADT原型文件,自行设计二叉树的ADT。)

(2)ADT的简单应用:使用该ADT设计并实现若干应用二叉树的算法设计。

应用4:要求设计一个非递归算法,实现二叉树的中序遍历。二叉树的存储结构的建立参见二叉树应用1。

提示:根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:

对于任一结点P,

(1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;

(2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;

(3)直到P为NULL并且栈为空则遍历结束。

参考函数原型:

//二叉树中序遍历的非递归算法 

template<class ElemType>

void InOrder( BinaryTree<ElemType> &T );     

辅助函数:

visit函数(具体功能根据实际需要,样例仅仅输出data域的信息)

template<class ElemType>

bool visit(BinaryTreeNode<ElemType> * root){

     

    if(!root) return false; 

    else{

        cout<<root->data<<" ";     

        return true;

    }

}

输入说明

第一行:表示无孩子或指针为空的特殊分隔符

第二行:二叉树的先序序列(结点元素之间以空格分隔)

输出说明

第一行:中序遍历的结果

输入范例

#
A B # C D # # E # # F # G # H # #

输出范例

B,D,C,E,A,F,G,H

AC代码

#include<iostream>
#include <sstream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<stack>
#include<vector>
#include <climits>
#define MAX_SIZE 100
using namespace std;
bool sign;
//结点
template<class ElemType>
struct BinaryTreeNode
{
       ElemType data;
       BinaryTreeNode<ElemType> *LChild, *RChild;
       BinaryTreeNode() : LChild(NULL), RChild(NULL){}
       BinaryTreeNode(const ElemType &item, BinaryTreeNode<ElemType> *Lptr = NULL, BinaryTreeNode<ElemType> *Rptr = NULL)
       {
           LChild = Lptr;
           RChild = Rptr;
           data = item;
       }
};
//二叉树
template<class ElemType>
class BinaryTree
{
   private:
      BinaryTreeNode<ElemType> *root;
   public:
      BinaryTree():root(NULL){}
      BinaryTree(const ElemType &item){root = new BinaryTreeNode<ElemType>(item);}
      void makeBinaryTree( const ElemType &item, BinaryTree &left, BinaryTree &right);
      int BinaryTreeSize( BinaryTreeNode<ElemType> *T ) const;
      bool BinaryTreeisEmpty() const{return root == NULL;}
      ElemType GetRootData() const{ return root->data;}
      void SetRoot(BinaryTreeNode<ElemType> * p){ root = p;}
      BinaryTreeNode<ElemType> * GetRoot() const{ return root;}
      bool PreOrderTraverse( BinaryTreeNode<ElemType> *T );  //前序遍历(递归)
      bool InOrderTraverse( BinaryTreeNode<ElemType> *T );  //中序遍历(递归)
      bool PostOrderTraverse( BinaryTreeNode<ElemType> *T );  //后序遍历(递归)
      BinaryTreeNode<ElemType>* CreateBinaryTree(vector<ElemType> &x, ElemType &empty, int &n);
};
template<class ElemType>
BinaryTreeNode<ElemType>* BinaryTree<ElemType>::CreateBinaryTree(vector<ElemType> &x, ElemType &empty, int &n)
{
        ElemType ch = x[n];//string
        n++;
        if (ch == empty)
        {
            return NULL;
        }
        else
        {
            BinaryTreeNode<ElemType> *Node = new BinaryTreeNode<ElemType>;
            Node->data = ch;
            Node->LChild = CreateBinaryTree(x, empty, n);
            Node->RChild = CreateBinaryTree(x, empty, n);
            return Node;
        }
}
//建立栈
stack<BinaryTreeNode<string>*> s;
//中序遍历,非递归实现
template<class ElemType>
bool visit(BinaryTreeNode<ElemType> * root)
{
    if(!root) return false;
    else
    {
        auto p=root;
       while(p||!s.empty())
       {
           if(p)
           {
               s.push(p);
               //cout<<" "<<p->data<<" ";
               p=p->LChild;
           }
           else
           {
               p=s.top();
               //一开始这写的是 auto p ,就运行不了,把auto 去了之后就可以了。原因:若在一个体里定义变量,出了这个体,变量就不在了;而我的外层循环中还有对p的判断,所以在这里定义变量时要慎重,不能再定义p从而把p变成了一个出了花括号就不存在的量。
               if(sign)
             {
               cout<<p->data;
               sign=false;
             }
               else cout<<','<<p->data;
               s.pop();
               p=p->RChild;

           }
       }
       return true;
    }
}

//前序非递归

template<class ElemType>
bool visit_PreOrde(BinaryTreeNode<ElemType> * root)
{
    if(!root) return false;
    else
    {
        auto p=root;
       while(p||!s.empty())
       {

           if(p)
           {if(sign)
           {
               cout<<p->data;
               sign=false;
           }
           else cout<<','<<p->data;
           if(p->RChild){s.push(p->RChild);}
           p=p->LChild;
           }

           else if(!s.empty())
           {
               p=s.top();
               s.pop();
           }
       }
       return true;
    }
}

/*一开始,我的前序遍历的部分为:(错的)
while(p||!s.empty())
       {
           if(sign) //这里应该现有if(p);
           {
               cout<<p->data;
               sign=false;
           }
           else cout<<','<<p->data;
           if(p->RChild){s.push(p->RChild);f++;}
           if(p->LChild)    
           {
               p=p->LChild;  

          //这里不该有if(p->LChild),p->LChild是否不为NULL是交给上面的if(p)判断的
           }
           else if(!s.empty())
           {
               p=s.top();
               s.pop();
           }
       }
*/

//后序非递归

template<class ElemType>
bool visit_PostOrder(BinaryTreeNode<ElemType> * root)
{
    if(!root) return false;
    else
    {
       auto p=root;
       while(p||!s.empty())
       {
           if(p&&p->tflag==0)
           {
              s.push(p);
              if(p->RChild&&p->RChild->tflag==0)s.push(p->RChild);
              p=p->LChild;
           }
           else if(s.empty())break;   

//这里一定要有结束循环条件,不然因为p(指向)A不为空,所以循环还会继续进行(死循环);且若栈s为空,那么接下来pop操作会RE。
           else
           {
               p=s.top();
               s.pop();
               if((p->LChild==NULL||p->LChild->tflag)&&(p->RChild==NULL||p->RChild->tflag))
               {
                   if(sign)
               {
                   cout<<p->data;
                   sign=false;
               }
               else cout<<','<<p->data;
               p->tflag=1;
               if(!s.empty())
               {p=s.top();
               s.pop();}
               }
           }
       }
       return true;
    }
}

//用户函数
template<class ElemType>
void InOrder( BinaryTree<ElemType> &T )
{
    visit(T.GetRoot());
}

template<class ElemType>
void PreOrde( BinaryTree<ElemType> &T )
{
    visit_PreOrde(T.GetRoot());

}

template<class ElemType>
void CreateTree(BinaryTree<ElemType> &T, ElemType &str, ElemType &empty)
{
    ElemType tmp;
    vector<ElemType> t;
    stringstream input_T(str);
    while(input_T >> tmp)
    {
         t.push_back(tmp);
    }
    BinaryTreeNode<ElemType> *root;
    int num = 0;
    root = T.CreateBinaryTree(t, empty, num);
    T.SetRoot(root);
}
int main()
{
    BinaryTree<string> T;
    string str;
    string empty;
    getline(cin,empty);
    getline(cin,str);
    CreateTree(T,str,empty);
    sign=true;
    InOrder(T);
    return 0;
}

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值