认识二叉树~

嗨~大家好,这里是春栀怡铃声 的博客~

"做你害怕的事,然后发现,不过如此~"

目录

树概念及结构

1.树的概念

2.树的相关概念

3.树的表示

二叉树概念及结构

1.二叉树的概念

​编辑

2.特殊的二叉树

3.二叉树的性质

4.二叉树的存储结构

二叉树顺序结构及实现

1.二叉树的顺序结构

2.堆的概念及结构

二叉树链式结构及实现

前置说明

二叉树的遍历

前序

​编辑

中序

​编辑

后序

结点个数以及高度等

二叉树结点个数

二叉树叶子结点个数

二叉树第k层结点个数

二叉树查找值为x的结点

二叉树的高度

二叉树的创建

通过前序遍历的数组构建二叉树


"假如《哈利·波特》的分院帽是个程序员...

它不会念咒语,而是掏出一棵发光的树:'勇敢?→左枝|智慧?→右枝|野心?→左左枝...'

3次选择,精准分院!这棵'决策树',正是二叉树的魔法变体✨"

让我们坐稳发车!探索二叉树的奥秘~

树概念及结构

1.树的概念

树---非线性顺序结构

有一个根节点,剩下的都是子节点,因为长相像一个倒过来的树,所以被称为树

A--根节点

用不同颜色圈起来的是不同子树 注意树形结构中,子树之间不能有交集,否则就不是树形结构

不是树:

2.树的相关概念

结点的度:一个结点含有的子树的个数称为该结点的度 例如:A的度为6,F的度为3

树的度:结点中最大的度即为树的度 例如图中树的度为6

叶子结点:度为0的结点为叶子节点。例如 B C H I......

双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点

孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 图中:B是A的孩子结点

兄弟结点:具有相同父结点的结点互称为兄弟结点;图:B、C是兄弟结点

结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;

树的高度或深度:树中结点的最大层次; 如图:树的高度为4

3.树的表示

我们来了解比较简单的孩子兄弟表示法

复制代码
typedef int DataType;
struct Node
{
 struct Node* firstChild1; // 第一个孩子结点
 struct Node* pNextBrother; // 指向其下一个兄弟结点
 DataType data; // 结点中的数据域
};

图形演示:

二叉树概念及结构

1.二叉树的概念

一棵二叉树是结点的一个有限集合,该集合: 1. 或者为空 2. 由一个根结点加上两棵别称为左子树和右子树的二叉树组成

2.特殊的二叉树

1.满二叉树

每一个父结点都有2个子结点

满二叉树是一种特殊的完全二叉树。

2.完全二叉树

对比维度 满二叉树 完全二叉树 💡 关键洞察
节点分布 所有层节点数达最大(第i层=2ⁱ⁻¹) 仅最后一层可能不满,且必须靠左连续 ✅ 完全二叉树允许"最后一排没坐满",但禁止"3号座空着,4号座有人"
叶子位置 仅出现在最后一层 可出现在最后一层或倒数第二层(最后一层叶子靠左) 🌰 6个节点的完全二叉树:节点3只有左孩子(度为1),叶子在第2、3层
节点度特性 非叶子节点度全为2,无度为1节点 度为1的节点只能有0个或1个,且只能有左孩子(绝无"只有右孩子") ⚠️ 强调:若遇"左空右不空",直接判定非完全二叉树!
节点总数 必为奇数(2ᵏ-1) 可奇可偶:偶数时有1个度为1节点,奇数时无 📐 深度公式: 满:k = log₂(n+1)

3.二叉树的性质

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

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

  2. 若规定根结点的层数为1,具有n个结点的满二叉树的深度,h=log₂ (n+1)

(ps: 是log以2 为底,n+1为对数)

  1. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有结点从0开始编号,则对于序号为i的结点有: 1. 若i>0,i位置结点的双亲序号:(i-1)/2 ;i=0,i为根结点编号,无双亲结点 2. i结点的左孩子结点 :i*2+1 右孩子结点:i*2+2

4.二叉树的存储结构

1.顺序存储

一般完全二叉树才用顺序存储,也就是数组存储,物理结构是数组,逻辑结构是二叉树

而现实中使用中只有堆才会使用数组来存储,关于堆我们下一章节会专门讲解。

2.链式存储

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

二叉树顺序结构及实现

1.二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。

现实中我们通常把堆 (一种二叉树) 使用顺序结构的数组来存储,需要注意的是这里的操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

2.堆的概念及结构

堆是一种特殊的数据结构,逻辑上是一棵完全二叉树,物理上用数组存储。它的核心特点是:父节点的值总是大于或小于子节点的值。

堆中某个结点的值总是不大于或不小于其父结点的值;

堆总是一棵完全二叉树。

更多堆的知识在这里~https://blog.csdn.net/wyx6666668888888/article/details/157655398?spm=1001.2014.3001.5501

二叉树链式结构及实现

前置说明

为了说明二叉树的遍历,我们先暂时用简单方式创建二叉树 在"二叉树的创建与销毁" 精讲怎么创建二叉树

复制代码
typedef int BTDataType;
typedef struct BinaryTreeNode
{
        BTDataType data;
        struct BinaryTreeNode* left;
        struct BinaryTreeNode* right;
}BTNode;

BTNode* BuyNode(int x)
{
        BTNode* newnode = (BTNode*)malloc(sizeof(BTNode)); //这里扩充的是整个结构体的大小
        //不能写成 BTDataType  这个!!
        if (newnode == NULL)
        {
                perror("malloc fail");
                return NULL;
        }
        newnode->data = x;
        newnode->left = NULL;
        newnode->right = NULL;

        return newnode;
}

BTNode* CreatBinaryTree()
{
        BTNode* node1 = BuyNode(1);
        BTNode* node2 = BuyNode(2);
        BTNode* node3 = BuyNode(3);
        BTNode* node4 = BuyNode(4);
        BTNode* node5 = BuyNode(5);
        BTNode* node6 = BuyNode(6);

        node1->left = node2;
        node2->left = node3;
        node1->right = node4;
        node4->left = node5;
        node4->right = node6;

        return node1;
}

BuyNode函数负责新插入的结点创建

CreatBinaryTree函数负责将每个结点联系起来,形成二叉树

这样就创建了6个节点的二叉树

二叉树的遍历

前序

遍历一个二叉树时 :先访问当前节点(根)->遍历左子树->遍历右子树

这个规则会递归地应用到每个子树上。

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

访问根结点 1

继续访问左子树 以2为根,访问2的左子树3

以3为根,访问左子树,左子树为NULL 返回根为2的结点,访问2的右子树,2的右子树为空返回到1,继续访问1的右子树

N 代表空 ,每一个框 框住的是一个小的树

中序

遍历一个二叉树时 :先遍历左子树-> 节点(根)->遍历右子树

这个规则会递归地应用到每个子树上。

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

从1出发 → 先处理左子树(2为根)

处理2的左子树(3为根):

3无左子树 → 访问3

3无右子树 → 返回

访问2:

2无左子树 → 访问2

2无右子树 → 返回

访问1

处理1的右子树(4为根):

4有左子树 → 访问5

5无左子树 → 访问5

5无右子树 → 返回

访问4的右子树 6

6无左子树->访问6

6无右子树->返回

✅ 最终结果:3 → 2→ 1→ 5→ 4→ 6

N 代表空 ,每一个框 框住的是一个小的树

后序
复制代码
void BackOrder(BTNode* root)  
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	BackOrder(root->left);
	BackOrder(root->right);
	printf("%d ", root->data);
}

遍历一个二叉树时 :先遍历左子树->遍历右子树->访问节点(根)

这个规则会递归地应用到每个子树上。

后序的解法与前序推导类似,希望大家可以自己讲给自己听~

结点个数以及高度等

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

使用递归,计算结点个数

二叉树叶子结点个数
复制代码
// 二叉树叶子结点个数
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);
}
二叉树第k层结点个数
复制代码
// 二叉树第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);
}

求k层节点个数,也就是求左子树和右子树的k-1层的结点个数之和

先判断如果根节点为空,说明为空堆

如果k==1 第一层只有根结点,返回为1

如果都不是,按照递归方式求左子树和右子树k-1层结点数之和

二叉树查找值为x的结点
复制代码
//查找x  
BTNode* BTFind(BTNode* root, BTData x)
{
	if (root == NULL)
		return NULL;
	
	if (root->val == x)
		return root;
	BTNode* node1=BTFind(root->left, x);
	if (node1) return node1;
	
	BTNode* node2=BTFind(root->right, x);
	if (node2) return node2;

	return NULL;
}

如果传入的二叉树为空,肯定没有要找的值

根节点找到就是x 返回根节点

如果根节点不是x 查找根节点的左结点,如果左结点找到了,返回,不用继续再右子树中找

所以需要记录node1 node2 可以用来判断有无找到x

二叉树的高度
复制代码
//树的高度
int TreeHeight(BTNode*root)
{
	if (root == NULL)
		return 0;
	return TreeHeight(root->left) > TreeHeight(root->right)? 
		   TreeHeight(root->left)+1: TreeHeight(root->right)+1;
}

二叉树的创建

通过前序遍历的数组构建二叉树

'#'--代表空 ,随意输入一串字符 "abc##de#g##f###"

复制代码
typedef struct Binarytree
{
	struct Binarytree* left;
	struct Binarytree* right;
	char val;
}BTNode;


BTNode* CreateBTNode(char* a, int* pi)
{
	if (a[(*pi)] == '#')
	{
		(*pi)++;
		return NULL;
	}
		

	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->val = a[(*pi)++];

	root->left = CreateBTNode(a, pi);
	root->right = CreateBTNode(a, pi);

	return root;
}

int main() {
	char a[100];
	scanf("%s", a);
	int i = 0;
	BTNode* root = CreateBTNode(a, &i);
	return 0;
}

设置字符数组a 存储输入数据,用'#' 代表空格

if (a[(*pi)] == '#')

{

(*pi)++;

return NULL;

}

如果在读取数组数据时,检测到了'#' 直接返回NULL 并且继续让下标+1

这里使用指针才能改变 i ,让 i 变化起来

BTNode* root = (BTNode*)malloc(sizeof(BTNode));

root->val = a[(*pi)++];

root->left = CreateBTNode(a, pi);

root->right = CreateBTNode(a, pi);

return root;

动态申请空间创建二叉树结点,

root->val = a[(*pi)++]; 先使用后++,不用担心错误

接下来的逻辑是按照前序的方式创建二叉树

感谢花时间阅读这篇内容!

如果觉得有价值,欢迎点赞支持、收藏备用,或分享给同行。你的认可,是我持续输出高质量内容的最大动力。

我们下期再见喽!!!

相关推荐
好物种草官2 小时前
广州儿童眼镜店深度测评:6家主流品牌横向对比与选择策略
大数据·人工智能·经验分享
仰泳的熊猫2 小时前
题目1434:蓝桥杯历届试题-回文数字
数据结构·c++·算法·蓝桥杯
ygklwyf2 小时前
模拟退火算法零基础快速入门
数据结构·c++·算法·模拟退火算法
曾浩轩2 小时前
C语言学习记录——BC119 最高分与最低分之差
c语言·笔记·学习
寄存器漫游者2 小时前
数据结构 二叉树与哈希表
数据结构·散列表
EmbedLinX2 小时前
Linux 之网络通信
linux·服务器·c语言·笔记·学习
Sayuanni%33 小时前
数据结构_Map和Set
java·数据结构
执着2593 小时前
力扣hot100 - 144、二叉树的前序遍历
数据结构·算法·leetcode
近津薪荼3 小时前
递归专题(4)——两两交换链表中的节点
数据结构·c++·学习·算法·链表