C++完成二叉树的创建及其它基本操作

/*(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相当多。其实按照老师的教学水平,我直接在遍历的时候完成输出,就已经很难了。但是我还是想试一试,因为这个想法很好。花了很多时间,最终胜利了,我的想法也落地了。

②和上次的双向链表比起来,这次我代码的书写规范了很多,希望下次再接再厉。

(感觉有点像小学生写日记啊……)

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值