二叉树的讲解

💓博主个人主页:不是笨小孩👀

⏩专栏分类:数据结构与算法👀 刷题专栏👀 C语言👀

🚚代码仓库:笨小孩的代码库👀

⏩社区:不是笨小孩👀

🌹欢迎大家三连关注,一起学习,一起进步!!💓

二叉树

二叉树的性质

1.若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) 个结点.

  1. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 2^h-1.

  2. 对任何一棵二叉树, 如果度为0其叶结点个数为n0 , 度为2的分支结点个数为02 ,则有n0 =n2 +1

  3. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2为底,n+1为对数)

  4. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:

  5. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点

  6. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子

  7. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

二叉树的链式结构

一般来说,二叉树分为二叉链和三叉链,二叉链就是结构里面一个左孩子节点,一个右孩子节点,三叉链多了一个父亲节点,我们比较经常见的都是二叉链的,所以我们主要讲的也是二叉链。

结构:

c 复制代码
typedef int BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

我们在看任意一颗二叉树时,都可以将它分为三部分,根,左子树,右子树 ,左子树也可看成根,左子树,右子树 ,右子树也可看成根,左子树,右子树,因此二叉树定义是递归式的,我们后面的代码也是主要靠递归来实现的。

二叉树的遍历

二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。

二叉树的遍历分为,前序遍历、中序遍历、后序遍历、层序遍历,其中前中后序遍历是递归定义的,而层序遍历是非递归遍历的。

前序遍历

前序遍历(Preorder Traversal 亦称先序遍历)------访问根结点的操作发生在遍历其左右子树之前。前序先访问根节点,再访问左子树,再访问右子树。

代码如下:

c 复制代码
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->data);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}

递归图:

大家可以根据这个递归展开图好好理解一下,后面的二叉树基本操作都是需要用递归来实现的。

中序遍历

中序遍历(Inorder Traversal)------访问根结点的操作发生在遍历其左右子树之中(间)。

代码如下:

c 复制代码
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreeInOrder(root->left);
	printf("%d ", root->data);
	BinaryTreeInOrder(root->right);

}

后序遍历

后序遍历(Postorder Traversal)------访问根结点的操作发生在遍历其左右子树之后。

代码如下:

c 复制代码
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreePostOrder(root->left);
	BinaryTreePostOrder(root->right);
	printf("%d ", root->data);
}

这三种遍历本质上都是一样的,理解清楚一个,另外两个就很简单了。

层序遍历

层序遍历和其他三种都不一样,设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

那这个要怎么实现呢?

我们需要借助我们的队列,我们可以先把根节点入到队列里,然后开始出队列,只不过每次出的时候如果它的左孩子不为空就将左孩子入队列,右孩子不为空就将右孩子入队列,以此类推。我们就是利用了队列的先进先出,我们就可以轻松地完成层序遍历。

代码如下:

c 复制代码
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
	{
		QueuePush(&q,root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front->left)
		{
			QueuePush(&q, front->left);
		}

		if (front->right)
		{
			QueuePush(&q, front->right);
		}
		printf("%d ", front->data);
	}
	printf("\n");
}

二叉树的销毁

二叉树的销毁很简单,我们需要遍历一遍二叉树,但是我们用那种遍历呢,如果用前序,那么就会销毁根节点,就找不到它的左孩子和右孩子,明显是不合适的,最好的情况就是我们先去销毁它的左孩子,再去销毁他的右孩子,然后再销毁根节点,所以这里我们使用后序遍历是比较合适的。

代码如下:

c 复制代码
// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);
}

二叉树的查找

二叉树的查找的基本思路也是遍历一遍二叉树,但是我们需要返回这个节点,这就给我们的难度增加了很多,我们这里想的是先看根节点是不是,如果不是就去他的左子树找,如果找到了就返回,否则就去它的右子树找,找到就返回该节点,最后都找不到我们就返回NULL.

代码如下:

c 复制代码
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}

	BTNode* left = BinaryTreeFind(root->left, x);
	if (left != NULL)
	{
		return left;
	}

	BTNode* right = BinaryTreeFind(root->right, x);
	if (right != NULL)
	{
		return right;
	}

	return NULL;
}

最后带大家看一下会给我们带来好运的树:

今天的分享就到这里,感谢大家的关注和支持!

相关推荐
努力写代码的熊大15 分钟前
链式二叉树数据结构(递归)
数据结构
yi.Ist16 分钟前
数据结构 —— 键值对 map
数据结构·算法
爱学习的小邓同学16 分钟前
数据结构 --- 队列
c语言·数据结构
s1533519 分钟前
数据结构-顺序表-猜数字
数据结构·算法·leetcode
闻缺陷则喜何志丹20 分钟前
【前缀和 BFS 并集查找】P3127 [USACO15OPEN] Trapped in the Haybales G|省选-
数据结构·c++·前缀和·宽度优先·洛谷·并集查找
lifallen7 小时前
Paimon LSM Tree Compaction 策略
java·大数据·数据结构·数据库·算法·lsm-tree
啟明起鸣7 小时前
【网络编程】简易的 p2p 模型,实现两台虚拟机之间的简单点对点通信,并以小见大观察 TCP 协议的具体运行
c语言·网络·tcp/ip·p2p
秋说12 小时前
【PTA数据结构 | C语言版】线性表循环右移
c语言·数据结构·算法
芯岭技术13 小时前
MS32C001-C单片机,32位ARM M0+内核,宽电压、低功耗、小封装。
c语言·arm开发·单片机
minji...15 小时前
数据结构 算法复杂度(1)
c语言·开发语言·数据结构·算法