二叉树的基本操作——数据结构实验报告

一、实验名称:二叉树

二、实验目的

1)熟练掌握二叉树的存储方式的具体实现过程,实现二叉树的基本操作及运算;

2)进一步巩固指针的用法,栈及队列的基本操作,进一步体会递归算法,学会综合应用。

三、实验要求

  1. 使用链式存储结构实现二叉树的存储;
  2. 运用递归及非递归实现二叉树的三种顺序遍历,及层次遍历;
  3. 运用递归实现二叉树中结点,深度的计算和二叉树的复制相关操作;
  4. 将所有相关操作整合成一个选择系统,以方便调用及实现。

四、实验环境

(1) 硬件环境:微机一台;

(2) 软件环境:windows7+VC++ 2010/6.0集成开发环境。

五、实验内容及测试分析

1)编程思想

 1.定义二叉树的二叉链表存储形式:包括结点数据域,左右孩子指针,  其中运用了递归操作。

 2.按照先序遍历的顺序递归创建二叉链表:递归出口:输入为#;

    否则,构建一个新的树结点,结点数据域为ch,再调用自 身分别创建结点的左子树,右子树。

3.递归实现先序遍历:递归的出口:树为空:

   否则,访问根结点,再调用自身遍历左子树及右子树;

   中序,后序,双序遍历的递归算法,在先序遍历的基础上改变访问根结点 的顺序即可。

4.非递归实现先序遍历:利用栈先进后出的思想,

初始化一个空栈S,指针p指向根结点;

申请结点空间q,存放栈顶弹出的元素;

当p非空或栈S非空时,执行以下循环:

如果p非空,则访问根结点,p进栈,p指向该结点左孩 子;

如果p为空,则弹出栈顶元素,将p指向该结点右子树。

5.非递归实现中序遍历:跟先序遍历算法相似,只需要在p为空时弹 出栈顶元素并访问根结点。

6.队列实现层次遍历:利用队列先进先出的特性;

    初始化一个空队列Q,指针p指向根结点,根结点入队;

   申请结点空间q,存放队列中出队的元素;

   当队列Q非空时,执行以下循环:

        队尾元素出队;访问根结点;

        如果该结点的左子树非空,左子树入队;

       如果该结点的右子树非空,右子树入队。

7.递归实现二叉树的复制:如果是空树,递归结束,否则执行以下操 作:

     申请一个新结点空间,复制根结点;

     递归复制左子树;

     递归复制右子树。

8.递归求二叉树的深度:如果是空树,递归结束,深度为0,否则执 行以下操作:

    递归计算左子树的深度记为m;

    递归计算右子树的深度记为n;

    如果m>n,二叉树的深度为m+1,否则为n+1。

9.递归求结点个数:如果是空树,则结点个数为0;否则,结点个数为 左子树的结点个数加上右子树的结点个数;

        同理可求度为1,度为2的结点个数,及叶子节点个数,只 需要加一个if语句,判断是否符合即可。

10.递归实现交换左右子树:如果是空树,递归结束;否则执行以下操 作:

      申请一个新结点空间t,t指向根结点的左子树;

      将根结点的右子指向根结点的左子树;

     根结点的左子树指向t;

     递归交换结点的左子树;

      递归交换结点的右子树。

11.上述算法实现以后,利用while语句做一个选择菜单界面,实现输入 数字执行相应操作。

2)程序代码

#include <iostream>

#define MAXSIZE 100

using namespace std;

typedef struct BiTNode{  //二叉树的存储结构 
	
	char data;
	
	struct BiTNode *lchild,*rchild;
	
}BiTNode,*BiTree;

typedef struct //栈的存储结构 
{
	
	BiTree *base;
	
	BiTree *top;
	
	int stacksize;
	
 } SqStack;
 
 void InitStack(SqStack &S) //构造一个空栈 
 {
 	
 	S.base=new BiTree[MAXSIZE];
 	
 	if(!S.base) exit(-2);
 	
 	S.top=S.base;
 	
 	S.stacksize=MAXSIZE;
 	
 }
 
 typedef struct{  //队列的存储结构 

	BiTree *base;  //存储空间的基指针

	int front; //头指针(伪指针)

	int rear;  //尾指针(伪指针)

}SqQueue;

//循环队列初始化

int InitQueue(SqQueue &Q)
{  //构造一个空队列Q

	Q.base=new BiTree[MAXSIZE];  //为队列分配一个最大容量为MAXSIZE的数组空间

	if(!Q.base) exit(-2);  //存储分配失败

	Q.front=Q.rear=0;  //头指针和尾指针置为0,队列为空

	return 1;

}

//循环队列判空
bool QueueEmpty(SqQueue Q)
{
	
	if(Q.front==Q.rear) return true;
	
	else return false;
	
 }

// 循环队列入队
int EnQueue(SqQueue &Q,BiTree e)
{
	
	if((Q.rear+1)%MAXSIZE==Q.front)
	
		return 0;
		
	Q.base[Q.rear]=e;
	
	Q.rear=(Q.rear+1)%MAXSIZE;
	
	return 1;
	
 } 
 
 //循环队列的出队
 int DeQueue(SqQueue &Q,BiTree &e) 
 {
 	
 	if(Q.front==Q.rear) return 0;
 	
 	e=Q.base[Q.front];
 	
 	Q.front=(Q.front+1)%MAXSIZE;
 	
 	return 1;
 	
 }
 
 //取队头元素
 BiTree GetHead(SqQueue Q)
 {
 	
 	if(Q.front!=Q.rear)
 	
 		return Q.base[Q.front];
 	
  } 
 
 bool StackEmpty(SqStack S)//判断栈是否为空 
 {
 	
 	if(S.top==S.base) return true;
 	
 	else return false;
 	
 }
 
 int Push(SqStack &S,BiTree e) //入栈 
 {
 	
 	if(S.top-S.base==S.stacksize)return -1;
 	
 	*(S.top++)=e;
 	
 	return 1;
 	
 }
 
 int Pop(SqStack &S,BiTree &e) //出栈 
 {
 	
 	if(S.top==S.base) return 0;
 	
 	e= *(--S.top);
 	
 	return 1;
 	
 }

void createBiTree(BiTree &T){  //先序遍历创建二叉树 递归实现 
	
	char ch;
	
	cin>>ch;
	
	if(ch=='#')T=NULL;   //递归出口 
	
	else{
		
		T=new BiTNode;
		
		T->data=ch;
		
		createBiTree(T->lchild); //创建左子树 
		
		createBiTree(T->rchild);  //创建右子树 
		
	}
	
} 



void FirstOrderTraverse(BiTree T){ //先序遍历二叉树,递归实现 
	
	if(T){
		
		cout<<T->data;
		
		FirstOrderTraverse(T->lchild);
		
		FirstOrderTraverse(T->rchild);
		
	}
	
}

void FirstOrderTraverse_1(BiTree T){  //先序遍历二叉树,非递归实现 
	
	SqStack S;
	
	InitStack(S);
	
	BiTree p,q;
	
	p=T;
	
	q=new BiTNode;
	
	while(p||!StackEmpty(S)){

	if(p){
		
		cout<<p->data;
		
		Push(S,p);
		
		p=p->lchild;
		
	}
	
	else {
		
		Pop(S,q);
		
		p=q->rchild;
		
	}
	
}
			
	
}

void InOrderTraverse(BiTree T){  //中序遍历二叉树,递归实现 
	
	if(T){
		
		InOrderTraverse(T->lchild);
		
		cout<<T->data;
		
		InOrderTraverse(T->rchild);
		
	} 
	
}

void InOrderTraverse_1(BiTree T) {  //中序遍历二叉树,非递归实现 
	
	SqStack S;
	
	InitStack(S);
	
	BiTree p,q;
	
	p=T;
	
	q=new BiTNode;
	
	while(p||!StackEmpty(S)){
		
		if(p){
			
			Push(S,p);
			
			p=p->lchild;
			
		}
		
		else {
			
			Pop(S,q);
			
			cout<<q->data;
			
			p=q->rchild;
			
		}
		
	}
	
}

void LastOrderTraverse(BiTree T){  //后序遍历二叉树,递归实现 
	
	if(T){
		
		LastOrderTraverse(T->lchild);
		
		LastOrderTraverse(T->rchild);
		
		cout<<T->data;
		
	}
	
} 

void OrderTraverse(BiTree T){  //层次遍历二叉树,队列实现 

	SqQueue Q;
	
	InitQueue(Q);
	
	EnQueue(Q,T);
	
	BiTree p,q;
	
	p=T;
	
	q=new BiTNode;
	
	while(!QueueEmpty(Q)){
		
		DeQueue(Q,q);
		
		cout<<q->data;
		
		if(q->lchild!=NULL)EnQueue(Q,q->lchild);
		
		if(q->rchild!=NULL)EnQueue(Q,q->rchild);
		
	}	

} 

void DoubleOrderTraverse(BiTree T) {  //双序遍历二叉树,递归实现 
	
	if(T){

		cout<<T->data;
		
		DoubleOrderTraverse(T->lchild);
		
		cout<<T->data;
		
		DoubleOrderTraverse(T->rchild);
		
	} 
	
}

void Copy(BiTree T,BiTree &NewT){ //复制二叉树

	if(T==NULL){

		NewT=NULL;

		return ;

	}

	else{

		NewT=new BiTNode;

		NewT->data=T->data;

		Copy(T->lchild,NewT->lchild);

		Copy(T->rchild,NewT->rchild);

	}

}

int Depth(BiTree T){  //计算二叉树的深度

	int m,n;

	if(T==NULL) return 0;

	else{

		m=Depth(T->lchild);

		n=Depth(T->rchild);

		if(m>n) return(m+1);

		else return(n+1);

	}

}

int NodeCount(BiTree T){ //统计结点个数

	if(T==NULL) return 0;

	else{

		return NodeCount(T->lchild)+NodeCount(T->rchild)+1;

	}

}

int NodeCount_0(BiTree T){ //统计叶子结点个数

	if(T==NULL)return 0;
	
	else if(T->lchild==NULL&&T->rchild==NULL)
	
			return NodeCount_0(T->lchild)+NodeCount_0(T->rchild)+1;
			
	else return NodeCount_0(T->lchild)+NodeCount_0(T->rchild);

}

int NodeCount_1(BiTree T){ //统计度为1的结点个数

	if(T==NULL)return 0;
	
	else if((T->lchild==NULL&&T->rchild!=NULL)||(T->lchild!=NULL&&T->rchild==NULL))
	
			return NodeCount_1(T->lchild)+NodeCount_1(T->rchild)+1;
			
	else return NodeCount_1(T->lchild)+NodeCount_1(T->rchild);

}

int NodeCount_2(BiTree T){ //统计度为2的结点个数

	if(T==NULL)return 0;
	
	else if(T->lchild!=NULL&&T->rchild!=NULL)
	
			return NodeCount_2(T->lchild)+NodeCount_2(T->rchild)+1;
			
	else return NodeCount_2(T->lchild)+NodeCount_2(T->rchild);


}

void changeChild(BiTree &T){ //交换左右子树

	BiTree t;

	if(T==NULL) return ;

	else {

		t=new BiTNode;

		t=T->lchild;

		T->lchild=T->rchild;

		T->rchild=t;

		changeChild(T->lchild);

		changeChild(T->rchild);

	}

}

void menu(){  //菜单界面
	
	cout<<"请选择操作:"<<endl;
	
	cout<<"      1.创建二叉树"<<endl;
	
	cout<<"      2.先序遍历二叉树"<<endl;
	
	cout<<"      3.中序遍历二叉树"<<endl;
	
	cout<<"      4.后序遍历二叉树"<<endl; 
	
	cout<<"      5.层序遍历二叉树"<<endl;

	cout<<"      6.双序遍历二叉树"<<endl;

	cout<<"      7.复制二叉树"<<endl;

	cout<<"      8.计算二叉树深度"<<endl;

	cout<<"      9.统计结点个数"<<endl;

	cout<<"      10.统计叶子结点个数"<<endl;

	cout<<"      11.统计度为1的结点个数"<<endl;

	cout<<"      12.统计度为2的结点个数"<<endl;
	
	cout<<"      13.交换左右子树"<<endl; 

	cout<<"      14.退出"<<endl;
	
} 

int main()
{
	
	BiTree T;
	
	int choose;
	
	menu();
	
	while(cin>>choose&&choose!=14){
		
		switch(choose){
			
			case 1:{
				
				cout<<"请按照先序遍历的顺序输入一个二叉树(空树以#标记):";
				
				createBiTree(T);
	 
				cout<<"二叉树创建成功!"<<endl;
				
				break;
			}
			
			case 2:{
				
				cout<<"先序遍历的结果为:"<<endl;
				
				FirstOrderTraverse(T);
				
				cout<<endl;
				
				FirstOrderTraverse_1(T);
				
				cout<<endl;
				
				break;
			}
			
			case 3:{
				
				cout<<"中序遍历的结果为:"<<endl;
				
				InOrderTraverse(T);
				
				cout<<endl;
				
				InOrderTraverse_1(T);
				
				cout<<endl;
				
				break;
			}
			
			case 4:{
				
				cout<<"后序遍历的结果为:"<<endl;
				
				LastOrderTraverse(T);
				
				cout<<endl;

				break;
			}
			
			case 5:{
				
				cout<<"层次遍历的结果为:"<<endl;
				
				OrderTraverse(T);
				
				cout<<endl;
				
				break;
			}

			case 6:{
				
				cout<<"双序遍历的结果为:"<<endl;
				
				DoubleOrderTraverse(T);
				
				cout<<endl;
				
				break;
			}

			case 7:{
				
				BiTree NewT;

				Copy(T,NewT);

				cout<<"复制完毕!"<<endl;

				cout<<"复制后的二叉树先序遍历为:"<<endl;

				FirstOrderTraverse(NewT);

				cout<<endl;
				
				break;
			}

			case 8:{
				
				cout<<"二叉树的深度为:";

				cout<<Depth(T);

				cout<<endl;
				
				break;
			}
				
			case 9:{
				
				cout<<"二叉树中结点个数为:";

				cout<<NodeCount(T);

				cout<<endl;
				
				break;
			}

			case 10:{
				
				cout<<"二叉树中叶子结点个数为:";

				cout<<NodeCount_0(T);

				cout<<endl;
				
				break;
			}
				
			case 11:{
				
				cout<<"二叉树中度为1的结点个数为:";

				cout<<NodeCount_1(T);

				cout<<endl;
				
				break;
			}

			case 12:{
				
				cout<<"二叉树中度为2的结点个数为:";

				cout<<NodeCount_2(T);

				cout<<endl;
				
				break;
			}

			case 13:{
				
				cout<<"已交换左右子树";

				changeChild(T);

				cout<<endl;
				
				break;
			}
			
			default:{
				
				cout<<"输入有误,请重新输入"<<endl; 
				
				break;
			}
			
		}
			
		menu();
		
	}	 
	
 }

输入数据:ABD##E##CF###

输出结果:2.先序遍历的结果为:

                     ABDECF

                     ABDECF

                     3.中序遍历的结果为:

                     DBEAFC

                     DBEAFC

                     4.后序遍历的结果为:

                     DEBFCA

                     5.层次遍历的结果为:

                     ABCDEF

                     6.双序遍历的结果为:

                     ABDDBEEACFFC

                     7.复制完毕!

                     复制后的二叉树先序遍历为:

                     ABDECF

                     8.二叉树的深度为:3

                     9.二叉树中结点个数为:6

                     10.二叉树中叶子结点个数为:3

                     11.二叉树中度为1的结点个数为:1

                     12.二叉树中度为2的结点个数为:2

                     13.已交换左右子树

                     14.退出

5)出现的问题及解决方法

注意改变栈及队列的指针数据类型。

六、实验总结

(1).树本身是一种非线性结构,在二叉树的基本操作的算法中多次利用到递归思想,二叉树本身的定义即为递归定义,调用自身定义左右孩子指针;后继的遍历等算法过程中也多次利用到递归;

(2).三种遍历算法的递归算法不同之处仅在于访问根结点和遍历左、右子树的先后关系,需要注意的是,任何一棵二叉树的叶子结点在先序,中序,后序遍历中,其访问的相对次序不变,包括双序遍历仅是在先序遍历的基础上,在访问右子树之前再次访问根结点;

(3).利用栈实现先序,中序遍历时,需要注意在定义栈的存储结构时,其头指针,尾指针的数据类型为指向根结点的指针的指针,队列实现层序遍历同理;

(4).本次实验是对之前所学栈,队列,递归的具体实现及综合应用,熟练掌握栈先进后出,队列先进先出的特性可以解决很多类似问题。 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值