【数据结构】二叉树的概念

01 概念

定义:二叉树既然叫二叉树,顾名思义即度最大为2的树称为二叉树。 它的度可以为 1 也可以为 0,但是度最大为 2 。

一颗二叉树是节点的一个有限集合,该集合:

① 由一个根节点加上两棵被称为左子树右子树的二叉树组成

② 或者为空

观察上图我们可以得出如下结论:

① 二叉树不存在度大于 2 的节点,换言之二叉树最多也只能有两个孩子。

② 二叉树的子树有左右之分,分别为左孩子右孩子。次序不可颠倒,因此二叉树是有序树。

注意:对于任意的二叉树都是由以下几种情况复合而成的:

02 满二叉树

定义:一个二叉树,如果每一层的结点数都达到了最大值(均为2),则这个二叉树就可以被称作为 "满二叉树" 。

换言之,如果一个二叉树的层数为 h,且总结点数为 2的 h 次方 - 1,那么它就是一个满二叉树。

计算公式:

① 已知层数求总数:

② 已知总数求层数:

03 完全二叉树

定义:对于深度为 h 的,有 n 个结点的二叉树,当且仅当其每一个结点都与深度为 h 的满二叉树中编号从 1 至 n 的结点一一对应时称之为完全二叉树。

前 h - 1 层是满的,最后一层不满,但最后一层从左到右是连续的。

完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。所以,满二叉树是一种特殊的完全二叉树(每一层节点均为2)。

常识:

① 完全二叉树中,度为 1 的最多只有 1 个。

② 高度为 的完全二叉树节点范围是

04 二叉树的性质

四点规则:

① 若规定根节点的层数为 1 ,则一颗非空二叉树的第 i 层上最多有 2 的 i - 1 次方个节点。

② 若规定根节点的层数为 1 ,则深度为 h 的二叉树最大节点数是 2 的 h 次方 - 1。

③ 对任何一棵二叉树,如果度为 0 其叶子结点个数为 n0,度为 2 的分支节点个数为 n2,则有n0 = n2 + 1。换言之,度为 0 的永远比度为 2 的多一个叶子结点。

假设二叉树有 n 个结点,从总结点数角度考虑:n = n0 + n1 + n2,从边的角度考虑,n 个结点的任意二叉树,总共有 n - 1 条边。因为度为 0 的结点没有孩子,故度为 0 的结点不产生边; 度为 1 的结点只有一个孩子,故每个度为 1 的结点产生一条边; 度为 2 的结点有 2 个孩子,故每个度为 2 的结点产生两条边,所以总边数为: n1+2*n2,故从边的角度考虑:n - 1 = n1 + 2*n2, n0 + n1 + n2 = n1 + 2*n2 - 1,即:n0 = n2 + 1

④ 若规定根节点的层数为 1 , 具有 n 个节点的满二叉树的深度 h = log(n + 1)。

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

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

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

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

05 二叉树的存储

1 数组存储

一般情况下使用数组来存储,只适合完全二叉树。

如果是非完全二叉树,会造成空间上的浪费。

2 链式存储

cpp 复制代码
typedef struct BinaryTreeNode
{
    struct BinTreeNode* left; // 左孩子
    struct BinTreeNode* right; // 右孩子
    DataType data; // 当前节点值域
}BTree;

06 二叉树的遍历

二叉树的遍历一般有四种方法:前序遍历,中序遍历,后序遍历,层序遍历。

1 前序遍历

先遍历根节点,再依次遍历左子树,右子树。而遍历左子树,又要先遍历根节点,再依次遍历左子树,右子树...直至遍历到空树。

cpp 复制代码
// 递归实现
void PreOrder(BTree*root)
{
    if (root == NULL)
        return;
    printf("%d ", root->data);//根节点
    PreOrder(root->left);//左子树
    PreOrder(root->right);//右子树
}

2 中序遍历

先遍历左子树,再依次遍历根节点,右子树。而遍历左子树,又要先遍历左子树,再依次遍历根节点,右子树...直至遍历到空树。

cpp 复制代码
// 递归实现
void Inorder(BTree*root)
{
    if (root == NULL)
        return;
    PreOrder(root->left);//左子树
    printf("%d ", root->data);//根节点
    PreOrder(root->right);//右子树
}

3 后序遍历

先遍历左子树,再依次遍历右子树,根节点。而遍历左子树,又要先遍历左子树,再依次遍历右子树,根节点...直至遍历到空树。

cpp 复制代码
// 递归实现
void Postorder(BTree*root)
{
    if (root == NULL)
        return;
    PreOrder(root->left);//左子树
    PreOrder(root->right);//右子树
    printf("%d ", root->data);//根节点
}

4 层序遍历

层序遍历顾名思义就是一层一层地遍历,这时就需要借助一个数据结构:队列来辅助实现。

cpp 复制代码
void leverOrder(BTree* root, Queue* pq)
{
	if (root == NULL)
		return;

	QueuePush(pq, root);//插入第一个节点
	while (!QueueEmpty(pq))//队列不为空
	{
		BTree* p = QueueFront(pq);
		printf("%d ", p->val);
		QueuePop(pq);
		if (p->left != NULL)//带入左孩子
		{
			QueuePush(pq, p->left);
		}
		if (p->right != NULL)//带入右孩子
		{
			QueuePush(pq, p->right);
		}
	}
}
相关推荐
散11214 小时前
01数据结构-01背包问题
数据结构
消失的旧时光-194315 小时前
Kotlinx.serialization 使用讲解
android·数据结构·android jetpack
Gu_shiwww15 小时前
数据结构8——双向链表
c语言·数据结构·python·链表·小白初步
苏小瀚16 小时前
[数据结构] 排序
数据结构
睡不醒的kun19 小时前
leetcode算法刷题的第三十四天
数据结构·c++·算法·leetcode·职场和发展·贪心算法·动态规划
吃着火锅x唱着歌19 小时前
LeetCode 978.最长湍流子数组
数据结构·算法·leetcode
Whisper_long19 小时前
【数据结构】深入理解堆:概念、应用与实现
数据结构
IAtlantiscsdn19 小时前
Redis7底层数据结构解析
前端·数据结构·bootstrap
我星期八休息19 小时前
深入理解跳表(Skip List):原理、实现与应用
开发语言·数据结构·人工智能·python·算法·list