0
点赞
收藏
分享

微信扫一扫

(数据结构)二叉树的建立与遍历

善解人意的娇娇 2022-04-30 阅读 101

目录

一、什么是二叉树?

二、实验内容

1.题目

2.具体实现

总结

以上就是今天要讲的内容,欢迎各位提出不同的看法~


前言

在学习了二叉树之后,对二叉树的概念还处于比较懵的状态,下面就一项实验报告来具体实现二叉树,目的是为了掌握二叉树的定义,并且实现二叉树的链式存储结构以及在链式存储结构中的三种遍历(前序、中序、后序)


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是二叉树?

二叉树(binary tree)是一个有限的结点集合,这个集合或则为空,或则由一个根结点和两颗互不相交的称为左子树(left subtree)和右子树(right subtree)的二叉树组成。

二叉树的抽象数据类型描述和树的抽象数据类型相似,这里不再介绍。显然,和树的定义一样,二叉树的定义也是一个递归定义。二叉树的结构简单、存储效率高,其运算算法也相对简单,而且任何m次数都可以转化为二叉树结构,可见二叉树的重要性。

二、实验内容

1.题目

1. 编写程序,建立一棵二叉树(以链表存储),对该二叉树进行遍历并输出该二叉树的前序,中序,后序遍历序列

2. 编写程序,建立一棵二叉树(以链表存储),实现二叉树左右子树的交换

3. 统计二叉树中叶子结点个数

2.具体实现

(1)首先创建一个二叉树的结构体,具体实现如下:

typedef struct node
{
	ElemType data;//存放结点值
	struct node *lchild;//左子树
	struct node *rchild;//右子树
}BTNode;

(2)创建一个二叉树

k的数值控制的是左右子树,k=1为左子树,k=2为右子树;因为str是主函数传入的字符串,所以j用来一个一个读入字符串中的单个字符;

void CreateBTree(BTNode *&b,char *str)//创建二叉树 
{
	BTNode *St[MaxSize],*p;                            //St数组作为顺序栈
	int top=-1,k,j=0;                                  //top为栈顶指针
	char ch;                                           
	b=NULL;                                            //初始时二叉链为空
	ch=str[j];
	while(ch!='\0')                                    //循环扫描str中的每个字符
	{
		switch(ch)
		{
			case '(':top++;St[top]=p;k=1;break;        //开始处理左孩子结点
			case ',':k=2;break;                        //开始处理右孩子结点
            case ')':top--;break;                      //栈顶结点的子树处理结束
			default:                                   
				p=(BTNode *)malloc(sizeof(BTNode));    //创建树的根节点
				p->data =ch;                           //存放结点值
				p->lchild=p->rchild=NULL;              //左右指针域置为空
				if(b==NULL)
					b=p;
				else                                    //已建立二叉树的根结点
				{
					switch(k)
					{
						case 1:St[top]->lchild=p;break;//新建结点作为栈顶结点的左孩子
						case 2:St[top]->rchild=p;break;//新建结点作为栈顶结点的右孩子
					}
				}
		}
		j++;                                            //继续扫描str
		ch=str[j];
	}
}

(3)实现三种遍历方式:

先序遍历:(NLR)                中序遍历:(LNR)                        后序遍历(LRN)

1、访问根结点                        1、中序遍历左子树                          1、后序遍历左子树

2、先序遍历根结点                 2、访问根结点                                 2、后序遍历右子树

3、先序遍历右结点                 3、中序遍历右子树                          3、访问根结点

通过下面的代码可以发现三种遍历的框架是相同的,唯一不同的是访问根结点的顺序不同,第一步访问根结点的为先序遍历,第二步访问根结点的为中序遍历,第三步访问根结点的为后序遍历

void PreOrder(BTNode *b)//先序遍历 
{
	if(b!=NULL)
	{
		printf("%c",b->data);//访问根结点
		PreOrder(b->lchild);//先序遍历左子树
		PreOrder(b->rchild);//先序遍历右子树
	}
}
void InOrder(BTNode *b)//中序遍历 
{
	if(b!=NULL)
	{
		InOrder(b->lchild);//中序遍历左子树
		printf("%c",b->data);//访问根结点
		InOrder(b->rchild);//中序遍历右子树
	 } 
}
void PostOrder(BTNode *b)//后序遍历 
{
	if(b!=NULL)
	{
		PostOrder(b->lchild);//后序遍历左子树
		PostOrder(b->rchild);//后序遍历右子树
		printf("%c",b->data);//访问根结点
	}
}

(4)叶子结点的个数:

下面的代码通过递归实现求叶子节点的个数,if((!b->lchild)&&(!b->rchild))       return 1;作为递归出口。Leaf(b->lchild)+Leaf(b->rchild)实现不断的递归,本实验求的是叶子节点个数,如若求得是结点个数,直接在 Leaf(b->lchild)+Leaf(b->rchild) 式子上加1即可,其余部分不做改变。

int Leaf(BTNode *b)//求叶子节点 
{
	if(!b)                                         //判断树是否为空
		return 0;
	else                                           //不为空是进行下一步
	{
		if((!b->lchild)&&(!b->rchild))
			return 1;
		else
			return Leaf(b->lchild)+Leaf(b->rchild);
	}
	
}

(5)二叉树的子树交换

void changeTree(BTNode *b)//交换二叉树的子树 
{
	if(b==NULL)
		cout<<"树为空,输出失败"<<endl;
	else
	{
		BTNode *temp;
		temp=b->lchild;
		b->lchild=b->rchild;
		b->rchild=temp;
		cout<<"树的左右子树交换成功"<<endl; 
	}
	
}

如上述代码,我在实验过程中,刚开始只考虑到交换了根结点的左右子树,而忽视了实验的要求是交换所有的左右子树,只创建了一个中间变量进行交换。

下面是改进了代码后的子树交换,创建了两个中间变量分别用于控制左子树和右子树,再利用递归巧妙地进行所有子树的交换

void changeTree(BTNode *b)//交换二叉树的子树 
{
	if(b!=NULL)
	{
		if(b->lchild!=NULL||b->rchild!=NULL)
		{
			BTNode *p,*q;
			p=b->lchild;
			q=b->rchild;
			
			b->lchild=q;
			b->rchild=p;
			
			changeTree(b->lchild);
			changeTree(b->rchild);
		}
	}
		
	
}

(6)主函数的具体实现:

int main()
{
	BTNode *tree;

	CreateBTree(tree,"a(b,c(d,e))");
	cout<<"前序遍历为:"; 
	PreOrder(tree);
	cout<<endl;
	cout<<"中序遍历为:";
	InOrder(tree);
	cout<<endl;
	cout<<"后序遍历为:"; 
	PostOrder(tree);
	cout<<endl;
	 
	cout<<"叶子结点个数为:";
	int number=Leaf(tree);
	cout<<number<<endl;
	
	changeTree(tree);
	cout<<"交换后的二叉树为:"<<endl;
	cout<<"前序遍历为:"; 
	PreOrder(tree);
	cout<<endl;
	cout<<"中序遍历为:";
	InOrder(tree);
	cout<<endl;
	cout<<"后序遍历为:"; 
	PostOrder(tree);
	cout<<endl;
	return 0;
}

总结

以上就是今天要讲的内容,欢迎各位提出不同的看法~
 

举报

相关推荐

0 条评论