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

数据结构 -- 树

一、树的基本概念

(一)定义

树是由 n(n ≥ 0) 个结点组成的有限集合,是一种非线性层次结构:

  • 当 n = 0 时,称为空树
  • 当 n > 0 时,存在唯一的根结点(无前驱结点),其余结点可划分为 m(m ≥ 0) 个互不相交的有限子集,每个子集都是一棵独立的子树

(二)结点与树的核心属性

概念定义
结点的度结点拥有的子树个数
叶结点(终端结点)度为 0 的结点(无子树,位于树的最底层)
分支结点(非终端结点)度不为 0 的结点(至少拥有一棵子树)
树的度树中所有结点的最大度数
深度 / 高度从根结点开始计数,根为第 1 层,子结点依次递增,树的最大层数即为深度 / 高度

(三)存储结构

  • 顺序存储:通过数组存储结点,需结合结点间的层次关系(如双亲下标)关联数据,适用于结构规则的树(如完全二叉树)。
  • 链式存储:通过指针记录结点的子树地址(如孩子指针、兄弟指针),灵活性高,适用于各类形态的树。

二、二叉树的基本概念

(一)定义

二叉树是 n(n ≥ 0) 个结点的有限集合,满足:

  • 当 n = 0 时,为空二叉树;
  • 当 n > 0 时,由根结点左子树右子树组成,且左、右子树互不相交,均为二叉树。

(二)核心特点

  1. 每个结点最多有 2 棵子树(左子树和右子树),即二叉树的度最大为 2;
  2. 左、右子树具有有序性,不可随意颠倒(如 “仅有左子树” 与 “仅有右子树” 是两种不同结构);
  3. 若结点仅有一棵子树,必须明确标注是左子树还是右子树。

三、特殊二叉树

类型定义
斜树所有结点仅含一棵子树,分为左斜树(仅左子树)和右斜树(仅右子树)
满二叉树深度为 k(k ≥ 1),所有分支结点均有左、右子树,且所有叶子结点在同一层
完全二叉树深度为 k(k ≥ 1),按层序编号后,与同深度满二叉树的结点编号完全一致

四、二叉树重要性质

  1. 第 i 层结点数上限:第 i(i ≥ 1) 层最多有 2^{i-1} 个结点(如第 3 层最多 4 个结点);
  2. 深度为 k 的结点总数上限:深度为 k(k ≥ 1) 的二叉树,最多有 2^k - 1 个结点(此时为满二叉树);
  3. 叶子结点与度为 2 的结点关系:任意非空二叉树中,叶子结点数 n₀ = 度为 2 的结点数 n₂ + 1(即 n₀ = n₂ + 1);
  4. 完全二叉树深度计算:含 n 个结点的完全二叉树,深度为 ⌊log₂n⌋ + 1⌊x⌋ 表示向下取整)。

五、二叉树遍历方式

二叉树遍历是按规则访问所有结点(每个结点仅访问一次),核心分为深度优先遍历(DFS)和广度优先遍历(BFS):

遍历类型具体方式遍历顺序
深度优先遍历前序遍历根结点 → 左子树 → 右子树
中序遍历左子树 → 根结点 → 右子树
后序遍历左子树 → 右子树 → 根结点
广度优先遍历层序遍历按层次从上到下、同层从左到右

前序遍历
规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子
树,再前序遍历右子树。如图,遍历的顺序为:ABDGHCEIF。

void PreOrder(TreeNode* root) {if (root == NULL) return;  // 空树,递归终止printf("%d ", root->data); // 访问根结点PreOrder(root->left);      // 递归遍历左子树PreOrder(root->right);     // 递归遍历右子树
}

中序遍历
规则是若树为空,则空操作返回,否则从根结点开始(注意并不是先访问根结
点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。如图,遍历的顺序为:GDHBAEICF。

void InOrder(TreeNode* root) {if (root == NULL) return;  // 空树,递归终止InOrder(root->left);       // 递归遍历左子树printf("%d ", root->data); // 访问根结点InOrder(root->right);      // 递归遍历右子树
}

3.后序遍历
规则是若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左
右子树,最后是访问根结点。如图,遍历的顺序为:GHDBIEFCA。

void PostOrder(TreeNode* root) {if (root == NULL) return;  // 空树,递归终止PostOrder(root->left);     // 递归遍历左子树PostOrder(root->right);    // 递归遍历右子树printf("%d ", root->data); // 访问根结点
}

遍历顺序:按树的层次从上到下、同一层从左到右依次访问所有结点,本质是 “按层访问”。​实现依赖:需借助队列(先进先出,FIFO),通过 “根结点入队 → 队头出队访问 → 左右子结点入队 → 循环至队空” 的逻辑实现。

void LevelOrder(TreeNode* root) {if (root == NULL) return;          // 空树,直接返回SeqQue* queue = CreateSeqQue(100); // 创建容量为 100 的队列EnterSeqQue(queue, root);          // 根结点入队while (!IsEmptySeqQue(queue)) {    // 队列非空,循环处理TreeNode* curr = GetHeadSeqQue(queue); // 取队头结点printf("%d ", curr->data);     // 访问当前结点QuitSeqQue(queue);             // 队头结点出队if (curr->left != NULL)        // 左子结点非空,入队EnterSeqQue(queue, curr->left);if (curr->right != NULL)       // 右子结点非空,入队EnterSeqQue(queue, curr->right);}DestroySeqQue(queue);              // 销毁队列,释放内存
}

http://www.dtcms.com/a/344654.html

相关文章:

  • Vue3+Ant-design-vue+SSE实现实时进度条
  • 前端快讯看这里
  • 基于导频的OFDM系统的信道估计(使用LS估计算法)
  • 突击复习清单(高频核心考点)
  • 【C++高阶六】哈希与哈希表
  • 线程池拒绝策略踩坑
  • uniappx与uniapp的区别
  • 【UniApp打包鸿蒙APP全流程】如何配置并添加UniApp API所需的鸿蒙系统权限
  • MySQL B+树索引使用
  • QT之QSS的使用方法和常用控件的样式设置
  • Qt 的事件类QEvent及其他子类事件的开发详解:从基础到实践的全方位指南
  • 高并发用户数峰值对系统架构设计有哪些影响?
  • Qt-窗口类部件
  • 极验demo(float)(一)
  • 数据结构:队列 二叉树
  • vivo“空间计算-机器人”生态落下关键一子
  • 码蹄杯进阶
  • 笔试——Day46
  • 基于SpringBoot+Vue框架的高校论坛系统 博客论坛系统 论坛小程序
  • 企业版Idea 无快捷键的启动方式
  • 和AI Agent一起读论文——A SURVEY OF S ELF EVOLVING A GENTS(五)
  • 如何监控和管理微服务之间的调用关系
  • 微信开发者工具:更改 AppID 失败
  • Unreal Engine Class System
  • 滑动窗口+子串+普通数组算法
  • Spring AI调用本地大模型实战
  • 【LINUX】CentOS7在VMware15中,从命令行界面切换到图形界面的异常汇总
  • Day10 Go语言深入学习(2)
  • 零成本 Redis 实战:用Amazon免费套餐练手 + 缓存优化
  • skywalking-agent与logback-spring.xml中的traceId自动关联的原理