数据结构——树

树(Tree)

1.1 树的基本概念

定义

树是n(n≥0)个结点的有限集合。

n = 0:空树

n > 0:满足以下条件:

  • 有且仅有一个特定的根结点

  • 其余结点可分为m个互不相交的有限集合T₁,T₂,...,Tₘ,每个集合又是一棵树,称为子树

术语

  • 结点的度:结点拥有的子树个数

  • 叶结点:度为0的结点

  • 分支结点:度不为0的结点

  • 树的度:树中最大的结点度数

  • 结点的层次:根为第1层,孩子为第2层,以此类推

  • 树的高度/深度:树中结点的最大层次

  • 有序树 vs 无序树:子树有顺序为有序树,否则为无序树

  • 森林:m(m≥0)棵互不相交的树的集合

树的特征

  • 动态储存:O(1)的插入和删除(在已知位置)

  • 查找速度:O(log n)(平衡树)

  • 层次结构:天然表达层次关系

1.2 树的存储结构

1. 双亲表示法(顺序存储)

#define MAXSIZE 100

typedef char DataType;

typedef struct {

DataType data;

int parent; // 双亲位置,根为-1

} PTNode;

typedef struct {

PTNode nodesMAXSIZE;

int n; // 结点数

} PTree;

特点

  • 查找双亲快:O(1)

  • 查找孩子慢:需要遍历整个数组

2. 孩子表示法(链式+顺序):

// 孩子结点

typedef struct CTNode {

int child; // 孩子在数组中的位置

struct CTNode *next; // 下一个孩子

} *ChildPtr;

// 表头结构

typedef struct {

DataType data;

ChildPtr firstchild; // 第一个孩子

} CTBox;

typedef struct {

CTBox nodesMAXSIZE;

int n, root; // 结点数和根位置

} CTree;

特点

  • 查找孩子快

  • 查找双亲慢

3. 孩子兄弟表示法(二叉树表示法)

typedef struct CSNode {

DataType data;

struct CSNode *firstchild; // 第一个孩子

struct CSNode *nextsibling; // 右兄弟

} CSNode, *CSTree;

特点

  • 将树转换为二叉树

  • 便于操作和遍历

二、二叉树(Binary Tree)

2.1 二叉树定义

n个结点的有限集合,该集合:

  • 要么为空树(n=0)

  • 要么由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成

2.2 二叉树特点

  • 每个结点最多有两个子树

  • 左子树和右子树有顺序,不能颠倒

  • 即使只有一个子树,也要区分左/右

2.3 特殊二叉树

1. 斜树

  • 左斜树:所有结点都只有左子树

  • 右斜树:所有结点都只有右子树

相当于线性表

2. 满二叉树

  • 所有分支结点都有左右子树

  • 所有叶子结点都在同一层

  • 深度为k的满二叉树有 2ᵏ - 1 个结点

3. 完全二叉树

对n个结点按层序编号(1~n)

编号i的结点与同样深度的满二叉树中编号i的结点位置完全相同

特点

  • 叶子结点只能出现在最下两层

  • 最下层叶子结点集中在左侧连续位置

  • 如果有度为1的结点,只能有一个,且只有左孩子

2.4 二叉树性质

  1. 性质1:第i层上最多有 2ⁱ⁻¹ 个结点(i≥1)

  2. 性质2:深度为k的二叉树至多有 2ᵏ - 1 个结点(k≥1)

  3. 性质3:对任何二叉树,如果叶子结点数为n₀,度为2的结点数为n₂,则:n₀ = n₂ + 1

  4. 性质4:具有n个结点的完全二叉树深度为 ⌊log₂n⌋ + 1

  5. 性质5:对完全二叉树编号(1~n):

  • i=1:根结点

  • i>1:双亲为 ⌊i/2⌋

  • 2i≤n:左孩子为2i

  • 2i+1≤n:右孩子为2i+1

2.5 二叉树存储

1. 顺序存储:

#define MAXSIZE 100

typedef char DataType;

// 完全二叉树用数组存储

DataType treeMAXSIZE + 1; // 下标从1开始

  • 适用:完全二叉树

  • 不适用:斜树(空间浪费)

2. 链式存储(二叉链表):

typedef struct BiTNode {

DataType data;

struct BiTNode *lchild, *rchild; // 左右孩子指针

} BiTNode, *BiTree;

2.6 二叉树遍历

深度优先遍历(DFS)

1. 先序遍历(根左右):

void PreOrder(BiTree T) {

if (T == NULL) return;

printf("%c ", T->data); // 访问根

PreOrder(T->lchild); // 遍历左子树

PreOrder(T->rchild); // 遍历右子树

}

2. 中序遍历(左根右):

void InOrder(BiTree T) {

if (T == NULL) return;

InOrder(T->lchild); // 遍历左子树

printf("%c ", T->data); // 访问根

InOrder(T->rchild); // 遍历右子树

}

3. 后序遍历(左右根):

void PostOrder(BiTree T) {

if (T == NULL) return;

PostOrder(T->lchild); // 遍历左子树

PostOrder(T->rchild); // 遍历右子树

printf("%c ", T->data); // 访问根

}

广度优先遍历(层序遍历)

void LevelOrder(BiTree T) {

if (T == NULL) return;

BiTree queueMAXSIZE; // 队列

int front = 0, rear = 0;

queuerear++ = T; // 根结点入队

while (front < rear) {

BiTree node = queuefront++;

printf("%c ", node->data);

if (node->lchild != NULL)

queuerear++ = node->lchild;

if (node->rchild != NULL)

queuerear++ = node->rchild;

}

}

2.7 遍历序列确定二叉树

  • 先序+中序:可唯一确定二叉树

  • 后序+中序:可唯一确定二叉树

  • 先序+后序:不能唯一确定(除非是满二叉树)

相关推荐
weixin19970108016几秒前
[特殊字符] 1688开放平台API Sign签名算法详解(Java / Python / PHP 实现)
java·python·算法
断点之下8 分钟前
数据结构从零开始④:堆——一种特殊的完全二叉树(附堆排序、TopK问题)
数据结构
WL学习笔记10 分钟前
顺序表详解
c语言·数据结构
sugar__salt12 分钟前
深入吃透前端线性数据结构:数组、栈、队列、链表核心原理与实战
前端·数据结构·链表
未若君雅裁12 分钟前
JVM 垃圾回收算法与分代回收机制
java·jvm·算法
智者知已应修善业18 分钟前
【51单片机初始化D5-D8亮,每按键按下D1到D4全亮,再按下恢复,如此循环】2024-3-26
c++·经验分享·笔记·算法·51单片机
8Qi844 分钟前
LeetCode 4:寻找两个正序数组的中位数 —— 二分查找法
java·算法·leetcode·职场和发展·二分查找
8Qi81 小时前
LeetCode 32:最长有效括号 —— 栈 + 标记法 题解
java·数据结构·算法·leetcode·职场和发展··括号匹配
机器学习之心1 小时前
198种组合算法+优化CNN-LSTM+SHAP分析+新数据预测+多输出!深度学习可解释分析,强烈安利,粉丝必备
深度学习·算法·cnn-lstm·shap分析·198种组合算法
Tairitsu_H1 小时前
[LC优选算法#3] 滑动窗口 | 将x减到0的最⼩操作数 | ⽔果成篮 | 字⺟异位词
c++·算法·leetcode·滑动窗口