/*(1)建立的二叉树;
节点的结构体为:
typedef struct
{
int num; /学号
char name[10]; /姓名
} student;
(2)完成前、中、后二叉树非递归遍历程序;
(3)从上至下、从左至右层次遍历程序;从上至下、从右至左层次遍历程序;
(选做从下至上、从左至右层次遍历程序)
*/
#include<iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
typedef struct
{ int num; //学号
char name[10]; //姓名
} student;
//预声明
template<class ElementType> class StackNode;
template<class ElementType> class ChainStack;
template<class ElementType> class QueueNode;
template<class ElementType> class ChainQueue;
template<class ElementType> class BinaryTreeNode;
template<class ElementType> class BinaryTree;
/*******************************************************************栈*******************************************************************/
template<class ElementType> //堆栈结点类
class StackNode
{ public:
ElementType data;
StackNode<ElementType> *link=NULL;
};
template<class ElementType> //堆栈类
class ChainStack
{ private:
StackNode<ElementType> *top;
public:
ChainStack()
{ top=NULL;
}
~ChainStack();
bool IsEmpty()
{ return top==NULL;
}
bool push(ElementType &newvalue); //进栈
bool pop(ElementType &result); //出栈
};
//析构函数
template<class ElementType>
ChainStack<ElementType>::~ChainStack()
{ StackNode<ElementType> *n;
while(top)
{ n=top->link;
delete top;
top=n;
}
}
//进栈运算
template<class ElementType>
bool ChainStack<ElementType>::push(ElementType &newvalue)
{ StackNode<ElementType> *p=new StackNode<ElementType>;
if(!p)
{ cout<<"生成新的栈结点失败!"<<'\n';
return false;
}
p->data=newvalue;
p->link=top;
top=p;
return true;
}
//出栈运算
template<class ElementType>
bool ChainStack<ElementType>::pop(ElementType &result)
{ if(IsEmpty())
{ cout<<"栈为空!"<<'\n';
return false;
}
result=top->data;
StackNode<ElementType> *p=top;
top=top->link;
delete p;
return true;
}
/*******************************************************************栈*******************************************************************/
/******************************************************************队列*******************************************************************/
template<class ElementType>
class QueueNode //队列结点类
{ public:
ElementType data;
QueueNode<ElementType> *link=NULL;
};
template<class ElementType>
class ChainQueue
{ public:
QueueNode<ElementType> *front;
QueueNode<ElementType> *rear;
public:
ChainQueue()
{ front=NULL;
rear=NULL;
}
~ChainQueue();
bool IsEmpty()
{ return front==NULL;
}
bool EnQueue(ElementType &newvalue); //进队
bool DeQueue(ElementType &result); //出队
void Display();
friend class BinaryTreeNode<ElementType>;
friend class BinaryTree<ElementType>;
};
//析构函数
template<class ElementType>
ChainQueue<ElementType>::~ChainQueue()
{ while(!IsEmpty())
{ QueueNode<ElementType> *p=front;
front=front->link;
delete p;
}
}
//进队运算
template<class ElementType>
bool ChainQueue<ElementType>::EnQueue(ElementType &newvalue)
{ QueueNode<ElementType> *p=new QueueNode<ElementType>;
p->data=newvalue;
p->link=NULL;
if(IsEmpty())
{ front=p;
rear=p;
}
else
{ rear->link=p;
rear=p;
}
return true;
}
//出队运算
template<class ElementType>
bool ChainQueue<ElementType>::DeQueue(ElementType &result)
{ if(IsEmpty())
{ cout<<"队列为空!"<<'\n';
return false;
}
result=front->data;
if(front==rear)
{ delete front;
front=NULL;
rear=NULL;
return true;
}
QueueNode<ElementType> *p=front;
front=front->link;
delete p;
return true;
}
/******************************************************************队列*******************************************************************/
template<class ElementType>
class BinaryTreeNode //二叉树结点类
{ public:
ElementType data;
BinaryTreeNode<ElementType> *LChild;
BinaryTreeNode<ElementType> *RChild;
public:
BinaryTreeNode()
{ LChild=NULL;
RChild=NULL;
}
BinaryTreeNode(ElementType &newvalue)
{ data=newvalue;
LChild=NULL;
RChild=NULL;
}
friend class BinaryTree<ElementType>;
};
template<class ElementType> //二叉树类
class BinaryTree
{ public:
BinaryTreeNode<ElementType> *btroot;
public:
BinaryTree()
{ btroot=NULL;
}
~BinaryTree()
{
}
bool IsEmpty()
{ return btroot==NULL;
};
BinaryTreeNode<ElementType>* MakeNode();
bool CreatBinaryTree(BinaryTreeNode<ElementType> *root,BinaryTreeNode<ElementType> *left,BinaryTreeNode<ElementType> *right);
bool DeleteBinaryTree(BinaryTreeNode<ElementType> *btroot);
void PreOrderRecursive(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q);
void InOrderRecursive(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q);
void PostOrderRecursive(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q);
void LevelOrder_U_L(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q);
void LevelOrder_U_R(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q);
void LevelOrder_D_L(BinaryTreeNode<ElementType> *btroot,ChainStack<ElementType> *q);
BinaryTreeNode<ElementType> * Delete(BinaryTreeNode<ElementType> *btroot);
friend class BinaryTreeNode<ElementType>;
};
//创建二叉树结点
template<class ElementType>
BinaryTreeNode<ElementType>* BinaryTree<ElementType>::MakeNode()
{ BinaryTreeNode<ElementType> *p;
int num;
char name[10];
cout<<"请输入学生学号:"<<'\n';
cin>>num;
cout<<"请输入学生姓名:"<<'\n';
cin>>name;
ElementType s;
s.num=num;
strcpy(s.name,name);
p=new BinaryTreeNode<ElementType>(s);
if(!p)
{ cout<<"创建结点失败!"<<'\n';
return NULL;
}
return p;
}
//创建二叉树
template<class ElementType>
bool BinaryTree<ElementType>::CreatBinaryTree(BinaryTreeNode<ElementType> *p,BinaryTreeNode<ElementType> *lchild,BinaryTreeNode<ElementType> *rchild)
{ p->LChild=lchild;
p->RChild=rchild;
}
/*****************************************************************************************************************************************************************/
//以下遍历的结果都先暂时存放在q队列中。main函数先把q队列的地址传过来,遍历结束后再让main函数遍历q队列,最后由main函数输出结果。(不足:遍历前没判断树是否为空。)
/*****************************************************************************************************************************************************************/
//前序遍历二叉树
template<class ElementType>
void BinaryTree<ElementType>::PreOrderRecursive(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q)
{ BinaryTreeNode<ElementType> *p=btroot;
ChainStack<BinaryTreeNode<ElementType>*> s;
BinaryTreeNode<ElementType> *result;
while(p||!s.IsEmpty())
{ if(p)
{ q->EnQueue(p->data);
s.push(p);
p=p->LChild;
}
else
{ s.pop(result);
p=result->RChild;
}
}
}
//中序遍历二叉树
template<class ElementType>
void BinaryTree<ElementType>::InOrderRecursive(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q)
{ BinaryTreeNode<ElementType> *p=btroot;
ChainStack<BinaryTreeNode<ElementType>*> s;
BinaryTreeNode<ElementType> *result;
while(p||!s.IsEmpty())
{ if(p)
{ s.push(p);
p=p->LChild;
}
else
{ s.pop(p);
q->EnQueue(p->data);
p=p->RChild;
}
}
}
//后序遍历二叉树 (注:后序遍历需要部分结点进栈两次。我的方法是:让结点两次进入不同的栈,第一次进入s,第二次进入m。)
template<class ElementType>
void BinaryTree<ElementType>::PostOrderRecursive(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q)
{ BinaryTreeNode<ElementType> *p=btroot;
ChainStack<BinaryTreeNode<ElementType>*> s,m;
BinaryTreeNode<ElementType> *result;
while(p||!s.IsEmpty())
{ if(p)
{ s.push(p);
p=p->LChild;
}
else
{ s.pop(p);
if(!(p->RChild))
{
q->EnQueue(p->data);
p=NULL;
}
else
{ if(!m.IsEmpty()&&m.pop(result)&&p==result) //判断是否已进栈两次
{ q->EnQueue(p->data);
p=NULL;
result=NULL;
}
else
{ if(result!=NULL) //判断result是否因为上面的if而退过栈。如果因为要判断p==result而让result退栈了,那现在重新把result塞回去
{ m.push(result);
s.push(p);
}
m.push(p);
p=p->RChild;
}
}
}
}
}
//从上至下从左到右遍历二叉树
template<class ElementType>
void BinaryTree<ElementType>::LevelOrder_U_L(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q)
{ BinaryTreeNode<ElementType> *p=btroot;
ChainQueue<BinaryTreeNode<ElementType>*> l;
l.EnQueue(p);
while(!l.IsEmpty())
{ l.DeQueue(p);
q->EnQueue(p->data);
if(p->LChild)
{ l.EnQueue(p->LChild);
}
if(p->RChild)
{ l.EnQueue(p->RChild);
}
}
}
//从上至下从右到左遍历二叉树
template<class ElementType>
void BinaryTree<ElementType>::LevelOrder_U_R(BinaryTreeNode<ElementType> *btroot,ChainQueue<ElementType> *q)
{ BinaryTreeNode<ElementType> *p=btroot;
ChainQueue<BinaryTreeNode<ElementType>*> l;
l.EnQueue(p);
while(!l.IsEmpty())
{ l.DeQueue(p);
q->EnQueue(p->data);
if(p->RChild)
{ l.EnQueue(p->RChild);
}
if(p->LChild)
{ l.EnQueue(p->LChild);
}
}
}
//从下至上从左到右遍历二叉树(注:这次遍历没有把结果放在q队列里,而是放在了q栈里。)
template<class ElementType>
void BinaryTree<ElementType>::LevelOrder_D_L(BinaryTreeNode<ElementType> *btroot,ChainStack<ElementType> *q)
{ BinaryTreeNode<ElementType> *p=btroot;
ChainQueue<BinaryTreeNode<ElementType>*> l;
l.EnQueue(p);
while(!l.IsEmpty())
{ l.DeQueue(p);
q->push(p->data);
if(p->RChild)
{ l.EnQueue(p->RChild);
}
if(p->LChild)
{ l.EnQueue(p->LChild);
}
}
}
//删除二叉树(注:利用递归)
template<class ElementType>
BinaryTreeNode<ElementType> * BinaryTree<ElementType>::Delete(BinaryTreeNode<ElementType> *btroot)
{ if(btroot)
{ Delete(btroot->LChild);
Delete(btroot->RChild);
delete btroot;
}
btroot=NULL;
return btroot;
}
int main()
{ BinaryTree<student> t;
cout << "*******************************操作选择*******************************" <<'\n';
cout << "1.生成二叉树" <<'\n';
cout << "2.前序遍历二叉树" <<'\n';
cout << "3.中序遍历二叉树" <<'\n';
cout << "4.后序遍历二叉树" <<'\n';
cout << "5.从上至下从左到右遍历二叉树" <<'\n';
cout << "6.从上至下从右到左遍历二叉树" <<'\n';
cout << "7.从下至上从左到右遍历二叉树" <<'\n';
cout << "8.删除二叉树" <<'\n';
cout << "**********************************************************************" <<'\n';
while(1)
{ int o;
cout<<"请输入操作数:"<<'\n';
cin>>o;
if(o>9||o<1)
{ cout<<"输入有误!请重新输入"<<'\n';
continue;
}
switch(o)
{ case 1:
{ int count=1;
BinaryTreeNode<student> *root,*l,*r;
//第一棵树
cout<<"请输入第"<<count++<<"个学生的信息:"<<'\n';
t.btroot=t.MakeNode();
cout<<"请输入第"<<count++<<"个学生的信息:"<<'\n';
l=t.MakeNode();
cout<<"请输入第"<<count++<<"个学生的信息:"<<'\n';
r=t.MakeNode();
t.CreatBinaryTree(t.btroot,l,r);
//第二棵树
root=l;
cout<<"请输入第"<<count++<<"个学生的信息:"<<'\n';
l=t.MakeNode();
cout<<"请输入第"<<count++<<"个学生的信息:"<<'\n';
r=t.MakeNode();
t.CreatBinaryTree(root,l,r);
//第三棵树
root=r;
cout<<"请输入第"<<count++<<"个学生的信息:"<<'\n';
l=t.MakeNode();
cout<<"请输入第"<<count++<<"个学生的信息:"<<'\n';
r=t.MakeNode();
t.CreatBinaryTree(root,l,r);
if(count==8)
{ cout<<"二叉树生成完毕!"<<'\n';
}
else
{ cout<<"二叉树生成失败!"<<'\n';
}
break;
}
case 2:
{ ChainQueue<student> q;
t.PreOrderRecursive(t.btroot,&q);
student s;
for(int i=1;i<=7;i++)
{ q.DeQueue(s);
cout<<"姓名:"<<s.name<<'\t'<<"学号:"<<s.num<<'\n';
}
break;
}
case 3:
{ ChainQueue<student> q;
t.InOrderRecursive(t.btroot,&q);
student s;
for(int i=1;i<=7;i++)
{ q.DeQueue(s);
cout<<"姓名:"<<s.name<<'\t'<<"学号:"<<s.num<<'\n';
}
break;
}
case 4:
{ ChainQueue<student> q;
t.PostOrderRecursive(t.btroot,&q);
student s;
for(int i=1;i<=7;i++)
{ q.DeQueue(s);
cout<<"姓名:"<<s.name<<'\t'<<"学号:"<<s.num<<'\n';
}
break;
}
case 5:
{ ChainQueue<student> q;
t.LevelOrder_U_L(t.btroot,&q);
student s;
for(int i=1;i<=7;i++)
{ q.DeQueue(s);
cout<<"姓名:"<<s.name<<'\t'<<"学号:"<<s.num<<'\n';
}
break;
}
case 6:
{ ChainQueue<student> q;
t.LevelOrder_U_R(t.btroot,&q);
student s;
for(int i=1;i<=7;i++)
{ q.DeQueue(s);
cout<<"姓名:"<<s.name<<'\t'<<"学号:"<<s.num<<'\n';
}
break;
}
case 7:
{ ChainStack<student> q;
t.LevelOrder_D_L(t.btroot,&q);
student s;
for(int i=1;i<=7;i++)
{ q.pop(s);
cout<<"姓名:"<<s.name<<'\t'<<"学号:"<<s.num<<'\n';
}
break;
}
case 8:
{ if(!(t.btroot=t.Delete(t.btroot)))
{ if(t.IsEmpty())
{ cout<<"二叉树为空!删除成功"<<'\n';
}
}
break;
}
}
}
return 0;
}
二叉树示意图:
运行结果:
感想:
①把遍历结果放在队列里面,再把队列的地址传给main函数,让main函数完成输出。自己实现这个过程非常困难。因为老师完全没教过。我在这个过程遇到的bug相当多。其实按照老师的教学水平,我直接在遍历的时候完成输出,就已经很难了。但是我还是想试一试,因为这个想法很好。花了很多时间,最终胜利了,我的想法也落地了。
②和上次的双向链表比起来,这次我代码的书写规范了很多,希望下次再接再厉。
(感觉有点像小学生写日记啊……)