【数据结构】二叉树

目录

  • 一、二叉树的链式结构
  • 二、二叉树链式存储结构的实现
    • [2.1 申请二叉树节点](#2.1 申请二叉树节点)
    • [2.2 创建一个简单的二叉树](#2.2 创建一个简单的二叉树)
    • [2.3 前序遍历](#2.3 前序遍历)
    • [2.4 中序遍历](#2.4 中序遍历)
    • [2.5 后序遍历](#2.5 后序遍历)
    • [2.6 二叉树的节点个数](#2.6 二叉树的节点个数)
    • [2.7 二叉树叶子节点个数](#2.7 二叉树叶子节点个数)
    • [2.8 二叉树第K层节点个数](#2.8 二叉树第K层节点个数)
    • [2.9 二叉树的深度或高度](#2.9 二叉树的深度或高度)
    • [2.10 二叉树查找值为`x`的节点](#2.10 二叉树查找值为x的节点)
    • [2.11 层序遍历](#2.11 层序遍历)
    • [2.12 二叉树的销毁](#2.12 二叉树的销毁)

前言 】我们在之前的博客中介绍了树的种类 ,并且在前两期博客中实现了堆数据结构及堆的实际应用博客 ,这期博客我们来实现二叉树的链式存储 。没有注意到之前博客的小伙伴可以移步至我的个人主页自行查看。链接:个人主页

数据结构专栏~

一、二叉树的链式结构

二叉树的链式存储结构 是指用链表来表示⼀棵二叉树,即用链表来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域左右指针域 ,左右指针分别用来给出该结点左孩子右孩子 所在的链结点的存储地址 。

如果没有左右孩子,那么对应的左右指针指向NULL即可。

知道它的结构 之后我们就可以用代码呈现出来二叉树的存储结构

c 复制代码
typedef char BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType val;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

我们依旧用结构体来实现二叉树的链式存储结构。

有了二叉树的存储结构,我们就可以对二叉树进行相关操作了,像前序遍历、中序遍历、后序遍历、层序遍历及计算结点个数等等操作。下面我将要实现的操作呈现下来,让大家能够跟上博主的节奏,下面我会对它们进行详细讲解。

c 复制代码
//申请节点
BTNode* BuyNode(BTDataType x);
//前序遍历------根左右
void preOrder(BTNode* root);
//中序遍历
void inOrder(BTNode* root);
//后序遍历
void postOrder(BTNode* root);
// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root);
// ⼆叉树叶⼦结点个数
int BinaryTreeLeafSize(BTNode* root);
// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root);
// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
//层序遍历
void leverOrder(BTNode* root);
// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root);

二、二叉树链式存储结构的实现

2.1 申请二叉树节点

  • 这里会用到动态内存申请函数 malloc,并且会对申请的空间进行检查
  • 将申请节点中储存的值赋值为目标值x
  • 申请节点后将左右指针置为
c 复制代码
//申请节点
BTNode* BuyNode(BTDataType x)
{
	BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
	if (newNode == NULL)
	{
		perror("malloc fail!");
		return NULL;
	}
	newNode->val = x;
	newNode->left = newNode->right = NULL;

	return newNode;
}

2.2 创建一个简单的二叉树

  • 我们现在已经能够申请节点 了,为了完成中序遍历等遍历操作我们要创建一个二叉树;
  • 这里我们将申请6个节点创建一个二叉树。
c 复制代码
BTNode* CreatTree()
{
	BTNode* nodeA = BuyNode('A');
	BTNode* nodeB = BuyNode('B');
	BTNode* nodeC = BuyNode('C');
	BTNode* nodeD = BuyNode('D');
	BTNode* nodeE = BuyNode('E');
	BTNode* nodeF = BuyNode('F');
    
	nodeA->left = nodeB;
	nodeA->right = nodeC;
	nodeB->left = nodeD;
	nodeB->right = nodeE;
	nodeC->left = nodeF;

	return nodeA;
}

从右侧内存中可以看出我们创建出了这样一棵二叉树

2.3 前序遍历

前序遍历访问顺序为:根结点、左子树、右子树。

c 复制代码
void preOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", root->val);
	preOrder(root->left);
	preOrder(root->right);
}

这就是前序遍历的递归代码 了,可能有很多人看完不能很理解,不要急,接下来,我来画图给大家分析。

另外这是我们的执行结果

上图就是详细的递归过程,最终我们的结果与程序执行的结果一样,大家可以停顿思考一下。

2.4 中序遍历

中序遍历访问顺序为:左子树、根结点、右子树。

c 复制代码
void inOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	inOrder(root->left);
	printf("%c ", root->val);
	inOrder(root->right);
}

运行结果:

这里的递归过程和前序遍历基本类似,就不在呈现画图过程了。

2.5 后序遍历

后序遍历访问顺序为:左子树、右子树、根结点。

c 复制代码
void postOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	postOrder(root->left);
	postOrder(root->right);
	printf("%c ", root->val);
}

运行结果:

2.6 二叉树的节点个数

二叉树的节点 = 左节点个数 + 右节点个数 + 根节点个数 。我们的代码依旧会采用递归 的方式实现,大家可以看一下代码是如何写的,代码写完后,我依旧会给大家画图解释

c 复制代码
//二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BinaryTreeSize(root->left) 
	+ BinaryTreeSize(root->right);
}

运行结果:


逐步画图:

这就是求二叉树节点个数的递归代码执行的过程。

2.7 二叉树叶子节点个数

二叉树的叶子节点个数等于左右孩子都为空的节点总和,所以在我们构建的树中,二叉树的叶子节点个数为3。

c 复制代码
// ⼆叉树叶⼦结点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return BinaryTreeLeafSize(root->left) 
		+ BinaryTreeLeafSize(root->right);
}

这段代码和求二叉树的节点总数的代码有很多相似之处,此处就不再画图解释。

运行结果:

2.8 二叉树第K层节点个数

假设我们要求二叉树第二层节点个数 ,此时K=2,我们用递归 实现的话,我们每递归一层相应的K就要减一,直到K为1时,说明到达了目标层数此时我们返回1,证明找到第K层的一个节点,将这样的节点数加起来即可 。下面让我们来看看递归代码怎么写。

c 复制代码
// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->left, k - 1)
		+ BinaryTreeLevelKSize(root->right, k - 1);
}

为了大家能够更好的了解代码,我们进行画图分析。

运行结果:

这里我们求解的是第2层的节点个数,所以结果是2。
分析结果:

2.9 二叉树的深度或高度

二叉树的深度 = 1 + MAX(左子树的高度,右子树的高度)。下面让我们一起看看代码怎么写。

c 复制代码
//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDeep = BinaryTreeDepth(root->left);
	int rightDeep = BinaryTreeDepth(root->right);

	return 1 + (leftDeep > rightDeep ? leftDeep : rightDeep);
}

运行结果:

2.10 二叉树查找值为x的节点

二叉树查找值为x的节点就比较好写了,只要递归 发现节点的值为x就返回节点即可,我们一起来看一下递归代码长什么样。

c 复制代码
// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->val == x)
	{
		return root;
	}
	BTNode* leftfind = BinaryTreeFind(root->left, x);
	if (leftfind)
	{
		return leftfind;
	}
	BTNode* rightfind = BinaryTreeFind(root->right, x);
	if (rightfind)
	{
		return rightfind;
	}

	return NULL;
}

运行测试:


2.11 层序遍历

二叉树的层序遍历 用到了【数据结构】队列 ,由于我们之前已经实现了队列这一数据结构,所以我们将会把队列代码拷贝过来,队列博客,详情请点击~

代码实现:

c 复制代码
//层序遍历
void leverOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		//去队头,出队头
		BTNode* pcur = QueueFront(&q);
		QueuePop(&q);
		printf("%c ", pcur->val);
		
		if (pcur->left)
		{
			QueuePush(&q, pcur->left);
		}
		if (pcur->right)
		{
			QueuePush(&q, pcur->right);
		}
	}
	QueueDestroy(&q);
}

代码中Queue是建立队列的封装函数,QueueInit是初始化队列的封装函数,QueueEmpty是判断队列是否为空的封装函数,QueueFront是取队头的封装函数,QueuePush是入队列的封装函数,QueuePop是出队头的封装函数。

运行结果:

过程详解:

2.12 二叉树的销毁

二叉树的销毁 过程中,我们已知根节点 ,所以我们首先要递归到最下面 ,然后从下往上依次销毁,也就是说要先销毁左右子树,不然你先销毁根节点就找不到左右子树了。

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

执行结果:

从右侧内存中可以看出,二叉树已经完全销毁了。

总结:
以上就是本期博客分享的全部内容啦!如果觉得文章还不错的话可以三连支持一下,你的支持就是我前进最大的动力!
技术的探索永无止境! 道阻且长,行则将至!后续我会给大家带来更多优质博客内容,欢迎关注我的CSDN账号,我们一同成长!
(~ ̄▽ ̄)~

相关推荐
槐月杰3 小时前
入门到精通,C语言十大经典程序
c语言·数据结构·算法
FAREWELL000754 小时前
C#进阶学习(一)简单数据结构类之ArrayList、Stack、Queue、Hashtable
数据结构·学习·c#·queue·arraylist·stack·hash table
烁3475 小时前
每日一题(小白)暴力娱乐篇25
java·数据结构·算法·娱乐
Tanecious.9 小时前
初阶数据结构--链式二叉树
数据结构
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧9 小时前
汉诺塔问题——用贪心算法解决
c语言·数据结构·算法·visualstudio·visual studio
飞鸟吟9 小时前
【数据结构与算法】——堆(补充)
c语言·数据结构·算法·排序算法
明月看潮生10 小时前
青少年编程与数学 02-016 Python数据结构与算法 18课题、组合数学算法
数据结构·python·算法·青少年编程
_x_w10 小时前
【10】数据结构的矩阵与广义表篇章
开发语言·数据结构·笔记·python·线性代数·链表·矩阵
ll77881112 小时前
C++学习之路,从0到精通的征途:string类的模拟实现
开发语言·数据结构·c++·学习·算法·职场和发展
飞川撸码12 小时前
【LeetCode 热题100】二叉树遍历入门:从中序遍历到层序与右视图(力扣94 / 102/199)(Go语言版)
算法·leetcode·golang·二叉树