当前位置: 首页 > news >正文

C语言数据结构——详细讲解《二叉树与堆的基本概念》

C语言数据结构——详细讲解《二叉树与堆的基本概念》

  • 前言
  • 一、树的基础概念
    • 1.1 为什么需要树?
    • 1.2 树的定义与结构
    • 1.3 树的核心术语
    • 1.3 树的核心术语
    • 1.4 树的表示方法(孩子兄弟表示法)
      • 结构定义
      • 为什么用孩子兄弟表示法?
    • 1.5 树的实际应用场景
  • 二、二叉树的概念与特性
    • 2.1 为什么重点研究二叉树?
    • 2.2 二叉树的定义与核心特点
    • 2.3 特殊的二叉树
      • 2.3.1 满二叉树
      • 2.3.2 完全二叉树
    • 2.4 二叉树的重要性质
  • 三、二叉树的存储结构
    • 3.1 顺序存储(数组存储)
      • 原理
      • 示例(完全二叉树的顺序存储)
    • 3.2 链式存储(二叉链)
      • 原理
      • 结构定义(C语言)
      • 示例(二叉链结构)
  • 四、堆的概念与基础实现
    • 4.1 堆是什么?
    • 4.2 堆的定义与核心条件
    • 4.3 堆的存储(数组顺序存储)
      • 示例1:大根堆的数组存储
      • 示例2:小根堆的数组存储


前言

  • 在上一篇博客中,我们探讨了队列这种线性数据结构,而此前学习的栈也属于线性结构——它们的元素都遵循“一对一”的线性逻辑关系。但在实际场景中,很多数据需要“一对多”的层级关系描述(比如文件系统、部门组织架构),此时线性结构就显得力不从心。
  • 今天,我们将进入非线性数据结构的世界,从最基础的“树”入手,逐步聚焦到应用最广泛的“二叉树”,最终讲解一种特殊的二叉树——“堆”。这三者层层递进,是后续学习高级数据结构(如红黑树、B+树)的核心基础。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的C语言数据结构专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12830540.html?spm=1001.2014.3001.5482


一、树的基础概念

在学习二叉树前,我们必须先理解“树”的本质——它是所有层级结构数据的“通用模型”,而二叉树是树的“简化版”。

1.1 为什么需要树?

在这里插入图片描述

假设我们要存储“电脑文件系统”的结构:C盘下有用户系统两个文件夹,用户下又有文档图片……
在这里插入图片描述

  • 如果用数组或链表(线性结构)存储,只能按“C盘→用户→文档→图片→系统”的顺序排列,无法体现“父子文件夹”的层级关系。而树的“一对多”结构,恰好能完美描述这种层级逻辑。
树的核心价值:解决“层级数据”的存储与访问问题,弥补线性结构在“一对多”关系中的不足。

1.2 树的定义与结构

树是由n(n≥0)个有限结点组成的具有层次关系的集合,满足以下规则:

  • 有且仅有一个根结点(如文件系统的“C盘”),根结点没有前驱结点;
  • 除根结点外,其余结点被分成m(m>0)个互不相交的子集(如“用户”“系统”文件夹),每个子集都是一棵独立的“子树”;
  • 子树之间不能相交(否则就变成了“图”,而非树);
  • 一棵有N个结点的树,必有N-1条边(每个结点除根外,都只通过一条边连接父结点)。

在这里插入图片描述

在这里插入图片描述

1.3 树的核心术语

树的术语较多,下面我们详细讲解一下

1.3 树的核心术语

树的术语较多,且需结合具体结构理解,我们以图示的树(根为A,子节点包含B、C、D、E、F、G等)为例,详细讲解:

术语定义示例(基于图示树)
父结点/双亲含有直接子结点的结点,是子结点的直接上层结点A是B、C、D、E、F、G的父结点(A直接包含这6个子结点)
子结点/孩子被父结点直接包含的结点,是父结点的直接下层结点B、C、D、E、F、G是A的子结点
结点的度结点拥有的直接子结点数量(仅统计 immediate child)A的度为6(有B、C、D、E、F、G共6个直接子结点)
树的度树中所有结点的度的最大值树的度为6(A的度最大,为6)
叶子结点度为0的结点(无任何直接子结点,是树的“最底层终端结点”)B、C、H、K、L、M、N、P、Q(这些结点没有子结点)
分支结点度不为0的结点(非叶子结点,可继续延伸子树)A、D、E、F、G、J(这些结点有直接子结点)
兄弟结点拥有相同父结点的结点B、C、D、E、F、G互为兄弟结点(它们的父结点都是A)
结点的层次从根开始计数,根为第1层,子结点为第2层,依此类推A在第1层;B、C在第2层;H、I在第3层;P、Q在第4层
树的高度/深度树中结点的最大层次(从根到最底层叶子的最长路径的层数)树的高度为4(最底层结点P、Q在第4层)
祖先根结点到该结点的路径上的所有结点P的祖先是A、E、J(路径:A→E→J→P)
子孙以该结点为根的子树中的所有结点(包括间接子结点)E的子孙是I、J、P、Q(E的子树包含这些结点)
森林m(m>0)棵互不相交的树的集合(多棵独立树的组合)若“以B为根的树”和“以C为根的树”相互独立,则它们组成森林

1.4 树的表示方法(孩子兄弟表示法)

树的存储需要同时保存“结点值”和“结点间的层次关系”,常用的是孩子兄弟表示法

结构定义

// 树的孩子兄弟表示法结点结构
typedef struct TreeNode {int data;                  // 结点存储的数据struct TreeNode* firstChild; // 指向该结点的“第一个子结点”(左起第一个)struct TreeNode* nextBrother; // 指向该结点的“下一个兄弟结点”(同一父结点的右侧兄弟)
} TreeNode;

在这里插入图片描述

为什么用孩子兄弟表示法?

  • 优点:只需两个指针(firstChildnextBrother),就能表示任意结构的树;且能将树“转化为二叉树”(把“兄弟关系”当作二叉树的“右子树”),后续可复用二叉树的操作逻辑。
  • 示例:若结点B有子结点E、F,且B的兄弟是C,则B->firstChild = EE->nextBrother = FB->nextBrother = C

1.5 树的实际应用场景

  • 文件系统:根目录(根结点)→ 文件夹(分支结点)→ 文件(叶子结点);
  • 组织架构:CEO(根结点)→ 部门总监(分支结点)→ 员工(叶子结点);
  • 数据库索引:B树、B+树(基于树结构实现高效查询)。

二、二叉树的概念与特性

树的结构灵活但复杂,而二叉树是树中最简单、最常用的类型——它限制了结点的度不超过2,大大降低了操作难度,且任意树都能转换为二叉树。

2.1 为什么重点研究二叉树?

在这里插入图片描述

既然树能表示任意层级关系,为什么还要专门学二叉树?答案是**“trade-off(权衡)”**:

  • 树的结点度可以是任意值(如一个结点有100个子结点),导致操作逻辑(如遍历、插入)非常复杂;
  • 二叉树限制“结点度≤2”,且子树有“左、右之分”(有序),操作逻辑统一,易于实现;
  • 关键:任意树都能通过“孩子兄弟表示法”转换为二叉树,学会二叉树就相当于掌握了所有树的核心操作。

2.2 二叉树的定义与核心特点

二叉树是结点的有限集合,满足:

  1. 集合为空(空二叉树);
  2. 由一个根结点 + 一棵“左子树” + 一棵“右子树”组成,且左、右子树均为二叉树;
  3. 核心约束
    • 结点的度≤2(最多有2个孩子:左孩子、右孩子);
    • 子树有“左右次序”(左子树和右子树颠倒后,是不同的二叉树)。

在这里插入图片描述

2.3 特殊的二叉树

二叉树中最常用的两种特殊类型是“满二叉树”和“完全二叉树”,后者是堆的基础。

2.3.1 满二叉树

在这里插入图片描述

  • 定义:每一层的结点数都达到最大值的二叉树(即第k层有2^(k-1)个结点)。
  • 公式:若满二叉树的层数为h,则总结点数为2^h - 1(等比数列求和:1+2+4+…+2^(h-1) = 2^h -1)。
  • 示例:h=3的满二叉树,总结点数=2^3 -1=7(第1层1个,第2层2个,第3层4个)。

2.3.2 完全二叉树

在这里插入图片描述

  • 定义:深度为h、有n个结点的二叉树,若其结点与“深度为h的满二叉树”中编号1~n的结点一一对应(编号从根开始,从上到下、从左到右),则为完全二叉树。
  • 核心特点:
    • 叶子结点只能出现在最后两层
    • 最后一层的叶子结点必须从左到右连续排列(不能有“左边空、右边有”的情况);
    • 满二叉树是“特殊的完全二叉树”(n=2^h -1时,完全二叉树就是满二叉树)。
关键区别:满二叉树要求“每一层都满”,完全二叉树只要求“最后一层左连续”——完全二叉树更灵活,且适合用数组存储(无空间浪费)。

2.4 二叉树的重要性质

以下性质基于“根结点层数为1”的规则,是后续堆操作的数学基础:

  1. 第i层最多结点数:若根为第1层,则第i层最多有2^(i-1)个结点(如第1层1=2^0 ,第2层2=2^1, 第3层4=2^2);
  2. 深度h的最大结点数:深度为h的二叉树,最多有2^h -1个结点(即满二叉树的结点数公式);
  3. 叶子结点与分支结点关系:对任意非空二叉树,若叶子结点数为n0,度为2的结点数为n2,则必有n0 = n2 + 1(推导:总边数=总结点数-1,且边数= n11 + n22,总结点数= n0 + n1 + n2,联立得n0 = n2 +1);
  4. 完全二叉树的父/子索引关系:若完全二叉树用数组存储(索引从0开始),则序号为i的结点:
    • 父结点序号:(i-1)/2(整数除法,如i=1的父结点是0,i=2的父结点是0);
    • 左孩子序号:2*i + 1(若2*i+1 < 总结点数,则存在左孩子);
    • 右孩子序号:2*i + 2(若2*i+2 < 总结点数,则存在右孩子)。

三、二叉树的存储结构

二叉树有两种存储方式,分别对应不同的应用场景:

3.1 顺序存储(数组存储)

原理

数组存储二叉树的结点,结点的位置(索引)由其在完全二叉树中的编号决定(参考“完全二叉树的父/子索引关系”)。

  • 适合场景:完全二叉树(无空间浪费);
  • 不适合场景:非完全二叉树(空结点需占用数组位置,空间利用率低)。

示例(完全二叉树的顺序存储)

若完全二叉树结点为[A, B, C, D, E, F](根为A,左子树B、D、E,右子树C、F),数组存储如下:
在这里插入图片描述

数组索引012345
结点值ABCDEF
  • A(0)的左孩子是B(1=20+1),右孩子是C(2=20+2);
  • B(1)的左孩子是D(3=21+1),右孩子是E(4=21+2);
  • C(2)的左孩子是F(5=22+1),右孩子不存在(22+2=6 ≥ 总结点数6)。

3.2 链式存储(二叉链)

原理

链表存储二叉树,每个结点包含“数据域”和两个“指针域”(分别指向左孩子和右孩子),称为“二叉链”。

  • 适合场景:所有二叉树(尤其是非完全二叉树,无空间浪费,灵活);
  • 缺点:无法像数组那样随机访问,需通过指针遍历。

结构定义(C语言)

// 二叉树的链式存储(二叉链)
typedef struct BinaryTreeNode {int data;                          // 结点数据struct BinaryTreeNode* leftChild;  // 指向左孩子的指针struct BinaryTreeNode* rightChild; // 指向右孩子的指针
} BTNode;

示例(二叉链结构)

对于结点[A, B, C, D](A的左是B,右是C;B的左是D),二叉链的结构为:

A
├─ leftChild → B
│  ├─ leftChild → D
│  └─ rightChild → NULL
└─ rightChild → C├─ leftChild → NULL└─ rightChild → NULL

四、堆的概念与基础实现

堆是特殊的完全二叉树,也是二叉树顺序存储的典型应用(如优先队列、堆排序)

4.1 堆是什么?

我们已经有了完全二叉树,为什么还要定义“堆”?因为堆在“快速获取最大值/最小值”场景中效率极高——堆的根结点永远是“最大值(大堆)”或“最小值(小堆)”,无需遍历整个树就能获取极值。

4.2 堆的定义与核心条件

堆是满足以下两个条件的完全二叉树:

  1. 结构条件:堆必须是一棵完全二叉树(保证可以用数组顺序存储,无空间浪费);
  2. 值条件(堆序性)
    • 大堆:每个父结点的值 ≥ 其左右子结点的值(根是最大值);
    • 小堆:每个父结点的值 ≤ 其左右子结点的值(根是最小值)。

在这里插入图片描述

4.3 堆的存储(数组顺序存储)

堆是完全二叉树,因此用数组存储最高效(无需额外指针,仅通过索引即可推导父子关系)。存储规则与完全二叉树一致,核心依赖“父、左孩子、右孩子的索引推导”:

  • 数组索引从0开始;
  • 对于序号为i的结点,可通过公式快速找到其亲属结点:
    • 父结点索引:(i - 1) / 2(整数除法,向下取整);
    • 左孩子索引:2 * i + 1(若计算结果 < 堆的元素个数,则左孩子存在);
    • 右孩子索引:2 * i + 2(若计算结果 < 堆的元素个数,则右孩子存在)。

示例1:大根堆的数组存储

在这里插入图片描述

大根堆的逻辑结构:根结点为70,左子结点30,右子结点5630的左子结点25、右子结点1556的右子结点10

数组存储结构[70, 30, 56, 25, 15, 10](数组索引0~5对应元素),各结点的亲属关系推导如下:

数组索引结点值父结点(索引/值)左孩子(索引/值)右孩子(索引/值)
070无(根结点)2*0+1=1 / 302*0+2=2 / 56
130(1-1)/2=0 / 702*1+1=3 / 252*1+2=4 / 15
256(2-1)/2=0 / 702*2+1=5 / 10无(2*2+2=6 ≥ 元素个数6
325(3-1)/2=1 / 30无(2*3+1=7 ≥ 6无(2*3+2=8 ≥ 6
415(4-1)/2=1 / 30无(2*4+1=9 ≥ 6无(2*4+2=10 ≥ 6
510(5-1)/2=2 / 56无(2*5+1=11 ≥ 6无(2*5+2=12 ≥ 6

示例2:小根堆的数组存储

在这里插入图片描述

小根堆的逻辑结构:根结点为10,左子结点15,右子结点5615的左子结点25、右子结点3056的右子结点70

数组存储结构[10, 15, 56, 25, 30, 70](数组索引0~5对应元素),亲属关系推导更能体现“小根堆父结点≤子结点”的特性:

数组索引结点值父结点(索引/值)左孩子(索引/值)右孩子(索引/值)
010无(根结点)2*0+1=1 / 152*0+2=2 / 56
115(1-1)/2=0 / 102*1+1=3 / 252*1+2=4 / 30
256(2-1)/2=0 / 102*2+1=5 / 70无(2*2+2=6 ≥ 6
325(3-1)/2=1 / 15无(2*3+1=7 ≥ 6无(2*3+2=8 ≥ 6
430(4-1)/2=1 / 15无(2*4+1=9 ≥ 6无(2*4+2=10 ≥ 6
570(5-1)/2=2 / 56无(2*5+1=11 ≥ 6无(2*5+2=12 ≥ 6

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的C语言数据结构专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12830540.html?spm=1001.2014.3001.5482

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述


文章转载自:

http://MHaU7K4j.gLjfd.cn
http://48VXaska.gLjfd.cn
http://Z7EGDUXX.gLjfd.cn
http://5XK5XS9e.gLjfd.cn
http://PV5asu0k.gLjfd.cn
http://D5oNhPHG.gLjfd.cn
http://OiXBir3L.gLjfd.cn
http://7Pspovf9.gLjfd.cn
http://L69ijAtV.gLjfd.cn
http://N7Gg3GYd.gLjfd.cn
http://xUOVvzB6.gLjfd.cn
http://9P5NqQGF.gLjfd.cn
http://d6IkddbX.gLjfd.cn
http://TSvAywCg.gLjfd.cn
http://QUsIadBg.gLjfd.cn
http://I924NFdq.gLjfd.cn
http://adPIePEz.gLjfd.cn
http://hcFV6yTL.gLjfd.cn
http://eJFvTdz3.gLjfd.cn
http://UsxNHrKm.gLjfd.cn
http://YnwVafUD.gLjfd.cn
http://z1eY4ncx.gLjfd.cn
http://UFkOa07y.gLjfd.cn
http://wnoJwUov.gLjfd.cn
http://UxjFuEN9.gLjfd.cn
http://Cwdiss19.gLjfd.cn
http://2TjbqWEr.gLjfd.cn
http://an4GlSim.gLjfd.cn
http://tpSt7FCp.gLjfd.cn
http://FaB0Gyrj.gLjfd.cn
http://www.dtcms.com/a/371244.html

相关文章:

  • 【杂类】I/O
  • import type在模块引入中的作用
  • MySQL入门指南:从安装到工作原理
  • 【基础-判断】一个页面可以存在多个@Entry修饰的组件。
  • MapStruct详解
  • 新的打卡方式
  • GESP 7/8级免CSP-J/S初赛!申请注意事项!今年已过,明年提前关注!
  • esbuild入门
  • 决策树概念与原理
  • More Effective C++ 条款31:让函数根据多个对象来决定怎么虚拟
  • Python列表:从入门到灵活运用的全攻略
  • 校园洒水车cad+三维图+设计说书
  • 机械硬盘的工作原理
  • 生命周期方法:didUpdateWidget
  • Pie Menu Editor V1.18.7.exe 怎么安装?详细安装教程(附安装包)​
  • ragflow MCP 调用核心提示词解析:逻辑闭环与优化方向
  • Knative Serving:ABP 应用的 scale-to-zero 与并发模型
  • Xsens帮助独立工作室创造引人注目的冒险游戏真实角色动画
  • 《动手学深度学习v2》学习笔记 | 2.4 微积分 2.5 自动微分
  • 【开题答辩全过程】以 哈尔滨裕丰草莓园管理系统为例,包含答辩的问题和答案
  • 国内外支持个人开发者的应用市场
  • 【LLIE专题】SIED:看穿0.0001lux的极致黑暗
  • ANSYS HFSS边界条件的认识
  • python系列之综合项目:智能个人任务管理系统
  • IOC为什么交由spring容器管理?
  • spring事务传播机制
  • LeetCode_数学
  • (nice!!!)(LeetCode 面试经典 150 题 ) 130. 被围绕的区域(深度优先搜索dfs || 广度优先搜索bfs)
  • 虚拟化技术
  • 【74页PPT】MES简介(附下载方式)