什么是树? 树(Tree)是n(n>=0)个节点的有限集
- 若 n = 0, 则称为空树
- 若 n > 0:
- 有且仅有一个特定的根(Root)的结点
- 其余结点可分为m (m>=0)个互不相交的有限集T1, T2, T3 … Tm
那什么又是森林呢? 很简单, 森林是 m (m>= 0) 棵互不相交的树的集合
树的存储结构
双亲表示法 (找双亲容易, 找孩子难)
每个结点有两个域, 数据域和双亲域
数据域 (data) : 存放结点自身的信息
双亲域 (parent): 该结点的父结点的下标
如:
该结点在数组中的下标 | data | parent |
---|---|---|
0 | R | -1 |
1 | A | 0 |
2 | B | 0 |
3 | C | 0 |
4 | D | 1 |
5 | E | 1 |
6 | F | 3 |
7 | G | 6 |
8 | H | 6 |
9 | I | 6 |
所以这棵树的形状为:
结点结构体:
typedef struct PTNode {
TeleType data; // 数据域
int parent; // 双亲位置域
} PTNode;
树结构:
#define MAX_TREE_SIZE 100
typedef struct{
PTNode [nodes[MAX_TREE_SIZE]; // 结点数组
int root;
int n; // 结点个数
} PTree;
孩子表示法
将每个结点的孩子用单链表存储起来, 然后每个结点由组成一个线性表, 用结构体数组表示
所以这棵树的形状为:
// 孩子结构体
typedef struct CTNode {
int child; // 记录孩子的数组下标
CTNode* next; // 指向下一个孩子
} *ChildPtr;
// 双亲结构体
typedef struct CTBox {
ElemType data;
ChildPtr firstchild; // 孩子链表的头指针
} CTBox;
// 树结构
typedef struct CTree {
CTBox nodes[MAX_SIZE]; // 结点结构体数组
int root;
int n;
} CTree;
孩子兄弟表示法
又名二叉树表示法, 二叉链表表示法
用二叉链表作为树的结构, 链表中的每个结点有两个指针域,分别指向第一个孩子结点, 下一个兄弟结点
typedef struct CSNode {
ElemType data;
CSNode* firstchild; // 第一个孩子
CSNode* nextsibling; // 下一个兄弟结点
} CSNode, *CSTree;
树与二叉树的相互转化
树 -> 二叉树
记忆:兄弟相连留长子
为什么要把树转化成二叉树? 因为一般的树相对于二叉树来说比较复杂, 而我们把它转化成二叉树后, 可以利用二叉树的算法来实现对树的操作
给定一棵树, 可以找到唯一与其对应的二叉树
- 加线: 在相邻兄弟之间加一条线
- 去线: 对每个节点, 除了其左孩子外, 去除它与其他孩子之间的线(关系)
如上面的孩子兄弟表示法, 本质就是用二叉链表表示一般的树:
二叉树 -> 树
记忆:左孩右右连双亲,去掉原来右孩线
是树变二叉树的逆过程
- 加线: 若p结点是父结点f的左孩子, 则将p结点的右孩子、右孩子的右孩子…沿分支找到的所有右孩子, 都与f用线连接起来
- 去线: 去掉原二叉树中所有结点与右孩子的连线
- 调整:将结点按层次排列,使其结构清楚,形成树结构
森林与二叉树的相互转化
森林 -> 二叉树
记忆:树变二叉根相连
- 将各棵树分别转化成二叉树
- 第一棵二叉树不动,从第二棵二叉树开始,依次把后一颗二叉树的根结点作为前一颗二叉树根结点的右孩子,用线连接起来
- 以第一颗树的根结点为二叉树的根,适当进行结构调整
如:
二叉树 -> 森林
记忆:去掉根的右孩孩,孤立二叉再还原
- 加线:将二叉树中根结点与其右孩子连线,及沿右分支搜索到的所有右孩子间的连线全部去掉,使之变成一个个孤立的二叉树
- 还原:将孤立的二叉树还原成树
如:
全部口诀:
树变二叉树:兄弟相连留长子
二叉树变树:左孩右右连双亲,去掉原来右孩线
森林变二叉树:树变二叉根相连
二叉树变树:去掉根的右孩孩,孤立二叉再还原
树与森林的遍历
树的遍历(类似二叉树的遍历)
先根(次序)遍历
若树不空,则先访问根结点,然后依次(一般从左到右)先根遍历各棵子树。
遍历结果:A B C D E
后根(次序)遍历
若树不空,则先依次(一般从左到右)后根遍历各棵子树,然后访问根结点。
遍历结果:B D C E A
层次遍历
若树不空,则从上到下一层一层访问每个结点
遍历结果:A B C E D
森林的遍历
将森林看作三部分:
- 森林中第一棵树的根节点
- 森林中第一棵树的子树森林
- 森林中其他树构成的森林
如:
先序遍历
若森林不空,则
- 访问森林中第一棵树的根结点;
- 先序遍历森林中第一棵树的子树森林;
- 先序遍历森林中(除第一棵树之外)其余树构成的森林。
中序遍历
若森林不空,则
- 中序遍历森林中第一棵树的子树森林;
- 访问森林中第一棵树的根结点;
- 中序遍历森林中(除第一棵树之外)其余树构成的森林。
这份笔记是我根据B站“青岛大学-王卓”王老师的教学视频写的,王老师讲的很好,感兴趣的话, 读者可以去看看