【数据结构】二叉树(前中后序遍历,多个相关题目).

🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸
在这里插入图片描述

今天带来的内容是二叉树

这里是下面要讲的知识内容🥳🥳🥳


一、⚽二叉树概念

1.结点的度:一个结点含有子树 的个数称为结点的度
2.叶结点:结点的度为0的点就是叶子结点
3.分支节点:结点的度不为0的结点
4.父结点:若一个结点含有子节点,那么这个结点就是该子节点的父结点
5.子结点
6.兄弟结点:拥有同一个父节点
7.树的度:一个树中的结点拥有的最大的度称为树的度,二叉树树的度最大为2。
8.结点的层次:从根开始定义起,根为第一层,根的子节点为第二层,以此类推
9.树的高度或深度:叶结点的最大层次 ,认为从1开始是最合理的,因为空树深度为0
10.结点的祖先:从根到该节点所经分支上的所有结点
11.子孙:以某结点为根的子树中任意结点都称为该节点的子孙
12.由m棵互不相交的树的集合称为森林

二、⚽树的结构体定义

树在现实生活当中其实就是一个文件系统,树的结构体定义可以有两种方式

1.🌈用data来存当前结点的值,然后用一个顺序表来存孩子结点的指针

//struct TreeNode
//{
//	int data;
//	struct 	TreeNode**childArray;
//	int sz;
//	int capacity;
//}
//

typedef struct TreeNode*SLDataType;
struct TreeNode
{
	int data;
	SeqList _child;//可以实现动态增长的
}

2.🌈树的最优表示法-左孩子右兄弟表示法

typedef int DataType;
struct TreeNode
{
	DataType data;
	struct TreeNode* _firstChild;
	struct TreeNode* _pNextBrother;
}

三、⚽二叉树的结构

1.二叉树每个结点的度而0或1或2,不存在大于2的结点
2.二叉树的子树有左子树和右子树之分,不能颠倒,二叉树是有序树
3.满二叉树,每一层都是满的
4.完全二叉树,除最后一层外都是满的,最后一层从左到右必须是连续的,如果不连续就不是完全二叉树
在这里插入图片描述

四、⚽二叉树的存储结构

1、🌈顺序存储

因为如果是用数组来存储,不管这颗二叉树是什么样的,都需要按完全二叉树的形式去开辟空间存储,这就有可能造成很多的浪费,最典型的就是只有一条分支走到底,而堆就是一颗完全二叉树,很适合用数组去存储,所以,普通的二叉树我们用链表存储(二叉链,三叉链)
在这里插入图片描述
因为需要去表示出父节点和子节点的关系,所以必须要这样,用数组去存储最大的优势就是能算出父节点与子节点的位置关系

2、🌈链式存储

二叉树的链式存储结构是指,用链表来表示一颗二叉树,也就是用链来指示元素的逻辑关系,通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子的存储地址。现在我们用的是二叉树,比如红黑树等高阶数据结构会用到三叉树

在这里插入图片描述

五、⚽三种最常见的遍历方式(递归)

三种遍历方式:
1.前序遍历(Preorder Traversal):访问根结点的操作发生在遍历其左右子树之前
2.中序遍历(Inorder Traversal):访问根结点的操作发生在遍历其左右子树之中
3.后序遍历(Postorder Traversal):访问根结点的操作发生在遍历其左右子树之后

1.🌈前序遍历

//前序遍历
void preorder(struct TreeNode*root)
{
	if(root==NULL)
	{
		return ;
	}
	printf("%d",root->data);
	preorder(root->lchild);
	preorder(root->rchild);
}

2.🌈中序遍历

//中序遍历
void inorder(struct TreeNode*root)
{
	if(root==NULL)
	{
		return;
	}
	inorder(root->lchild);
	printf("%d",root->data);
	inorder(root->rchild);
}

3.🌈后序遍历

//后序遍历
void torder(struct TreeNode*root)
{
	if(root==NULL)
	{
		return;
	}
	torder(root->lchild);
	torder(root->rchild);
	printf("%d",root->data);
}

分而治之,大问题化成小问题

六、⚽二叉树求结点树,高度等等…

1.🌈求二叉树的size

int TreeSize(struct TreeNode*root)
{
	if(root==NULL)
		return 0;
	return TreeSize(root->left)+TreeSize(root->right)+1;
	//也可以用三目
	//return root==NULL ? 0 : TreeSize(root->left)+TreeSize(root->right)+1;
}

2.🌈求二叉树叶子数

int TreeLeafSize(struct TreeNode*root)
{
	if(root==NULL)
	return 0;
	if(root->left==NULL&&root->right==NULL)
	return 1;
	return TreeLeafSize(root->left)+TreeLeafSize(root->right);
}

3.🌈求k层的节点数

int TreeKLevel(struct TreeNode*root,int k)
{
	assert(k>=1);//断言,k必须>=1;
	if(root==NULL)
		return 0;
	if(k==1)
		return 1;
	return TreeKLevel(root->left,k-1)+ TreeKLevel(root->right,k-1);
}

4.🌈找某个结点

TreeNode*TreeFind(struct TreeNode*root,DataType x)
{
	if(root==NULL)
		return NULL;
	if(root->val==x)
		return root;
	
	struct TreeNode*ret1=TreeFind(root->left);
	if(ret1)
		return ret1;
	struct TreeNode*ret2=TreeFind(root->right);
	if(ret2)
		return ret2;
	
	return NULL;
}

5.🌈求树的高度

int TreeDepth(struct TreeNode*root)
{
	if(root==NULL)
	return 0;
	int leftHigh=TreeDepth(root->left);
	int rightHign=TreeDepth(root->right);
	
	return 1+(leftHigh>rightHign?leftHign:rightHign);
}

6.🌈层序遍历,判断是否为完全二叉树

从打印的角度如果把NULL也打印出来,完全二叉树一定是NULL后面全是NULL,而不是完全二叉树的话,NULL和有效数据之间是分开的
层序遍历一般借助队列来完成

bool IsTreeComplete(BTNode*root)
{
	Queue q;
	QueueInit(&q);
	if(root!=NULL)
		QueuePush(&q,root);
		//因为会
	while(!QueueEmpty(&q))
	{
		BTNode*front=QueueFront(&q);
		//取队头数据
		QueuePop(&q);
		if(front)
		{
			QueuePush(&q,front->left);
			QueuePush(&q,front->right);
			//子树是NULL就push  NULL进去
		}
		else
		{
			//遇到NULL之后跳出层序遍历
			break;
		}
	}
	//如果后面全是空,则是完全二叉树
	//如果后面还有非空,则不是完全二叉树
	while(!QueueEmpty(&q))
	{
		BTNode*front=QueueFront(&q);
		QueuePop(&q);
		if(front)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

七、⚽总结

二叉树用递归的地方比较多,递归的思想要好好的想一想,下一篇我们继续学习堆(一种数据结构)
在这里插入图片描述

评论 35
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猪皮兄弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值