附: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;
}