完成并查集
@@ -83,3 +83,40 @@ $n$ 个结点的树中只有 $n-1$ 条边。
|
||||
- 后序线索二叉树
|
||||
|
||||
#### 4.7.2. [线索二叉树的构造](binary-tree-traversal/README.md#72-线索二叉树的构造)
|
||||
|
||||
## 5. [树的存储结构](tree-storage/README.md#树的存储结构)
|
||||
|
||||
- [双亲表示法](tree-storage/README.md#1-双亲表示法)
|
||||
- [孩子表示法](tree-storage/README.md#2-孩子表示法)
|
||||
- [孩子兄弟表示法](tree-storage/README.md#3-孩子兄弟表示法)
|
||||
|
||||
| | 优点 | 缺点 |
|
||||
| -------------- | ------------------------------------------------ | ------------------------ |
|
||||
| 双亲表示法 | 寻找结点的双亲结点效率高 | 寻找结点的孩子结点效率低 |
|
||||
| 孩子表示法 | 寻找结点的孩子结点效率高 | 寻找结点的双亲结点效率低 |
|
||||
| 孩子兄弟表示法 | 寻找结点的孩子结点效率高,方便实现树转换为二叉树 | 寻找结点的双亲结点效率低 |
|
||||
|
||||
## 6. [树与森林](tree-traversal/README.md#树与森林)
|
||||
|
||||
- [树与二叉树的转换](tree-traversal/README.md#1-树与二叉树的转换)
|
||||
- [森林与二叉树的转换](tree-traversal/README.md#2-森林与二叉树的转换)
|
||||
|
||||
[树的遍历](tree-traversal/README.md#3-树的遍历)
|
||||
|
||||
- [先根遍历](tree-traversal/README.md#31-先根遍历)
|
||||
- [后根遍历](tree-traversal/README.md#32-后根遍历)
|
||||
- [层次遍历](tree-traversal/README.md#33-层次遍历)
|
||||
|
||||
[森林的遍历](tree-traversal/README.md#4-森林的遍历)
|
||||
|
||||
- [先序遍历](tree-traversal/README.md#41-先序遍历)
|
||||
- [中序遍历](tree-traversal/README.md#42-中序遍历)
|
||||
|
||||
| 树 | 森林 | 二叉树 |
|
||||
| -------- | -------- | -------- |
|
||||
| 先根遍历 | 先序遍历 | 先序遍历 |
|
||||
| 后根遍历 | 中序遍历 | 中序遍历 |
|
||||
|
||||
## 7. [树的应用](tree-applications/README.md)
|
||||
|
||||
- [并查集](tree-applications/README.md#1-并查集)
|
||||
|
||||
48
ch5/tree-applications/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 树的应用
|
||||
|
||||
## 1. 并查集
|
||||
|
||||
一种简单的集合表示。
|
||||
|
||||
通常用书的双亲表示法作为并查集的存储结构。
|
||||
|
||||
通常用数组元素的下标代表元素名,用根结点的下标代表子集合名,根结点的双亲结点为负数。
|
||||
|
||||
- `Initial(S)`:将集合 $S$ 的每个元素都初始化为只有一个单元素的子集合。
|
||||
- `Union(S, Root1, Root2)`:将集合 $S$ 的子集合(互不相交) $Root2$ 并入到子集合 $Root1$。
|
||||
- `Find(S, x)`:查找集合 $S$ 中单元素 $x$ 所在的子集合,并返回该子集合的名字。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
```cpp
|
||||
#define SIZE 100
|
||||
void Initial(int S[])
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
S[i] = -1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
int Find(int S[], int x)
|
||||
{
|
||||
while (S[x] >= 0)
|
||||
{
|
||||
x = S[x];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
void Union(int S[], int Root1, int Root2)
|
||||
{
|
||||
S[Root2] = Root1;
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
BIN
ch5/tree-applications/and-search-set1.png
Normal file
|
After Width: | Height: | Size: 357 KiB |
BIN
ch5/tree-applications/and-search-set2.png
Normal file
|
After Width: | Height: | Size: 351 KiB |
BIN
ch5/tree-applications/and-search-set3.png
Normal file
|
After Width: | Height: | Size: 477 KiB |
62
ch5/tree-storage/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# 树的存储结构
|
||||
|
||||
## 1. 双亲表示法
|
||||
|
||||
采用一组连续的存储空间来存储每个结点,同时在每个结点中增设一个伪指针,指示双亲结点在数组的位置。
|
||||
|
||||
根结点的下标为 $0$,其伪指针域为 $-1$。
|
||||
|
||||
```cpp
|
||||
#define MAX_TREE_SIZE 100
|
||||
typedef struct
|
||||
{
|
||||
ElemType data;
|
||||
int parent;
|
||||
} PTNode;
|
||||
typedef struct
|
||||
{
|
||||
PTNode nodes[MAX_TREE_SIZE];
|
||||
int n;
|
||||
} PTree;
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 2. 孩子表示法
|
||||
|
||||
将每个结点的孩子结点都用单链表链接起来形成一个线性结构,$n$ 个结点具有 $n$ 个孩子链表。
|
||||
|
||||
```cpp
|
||||
#define MAX_TREE_SIZE 100
|
||||
typedef struct
|
||||
{
|
||||
int child;
|
||||
struct CNode *next;
|
||||
} CNode;
|
||||
typedef struct
|
||||
{
|
||||
ElemType data;
|
||||
struct CNode *child;
|
||||
} PNode;
|
||||
typedef struct
|
||||
{
|
||||
PNode nodes[MAX_TREE_SIZE];
|
||||
int n;
|
||||
} CTree;
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 3. 孩子兄弟表示法
|
||||
|
||||
以二叉链表作为树的存储结构,又称二叉树表示法。(左孩子右兄弟)
|
||||
|
||||
```cpp
|
||||
typedef struct CSNode
|
||||
{
|
||||
ElemType data;
|
||||
struct CSNode *firstchild, *nextsibling;
|
||||
} CSNode, CSTree;
|
||||
```
|
||||
|
||||

|
||||
BIN
ch5/tree-storage/child-brother-representation.png
Normal file
|
After Width: | Height: | Size: 316 KiB |
BIN
ch5/tree-storage/child-representation.png
Normal file
|
After Width: | Height: | Size: 341 KiB |
BIN
ch5/tree-storage/parental-representation.png
Normal file
|
After Width: | Height: | Size: 294 KiB |
59
ch5/tree-traversal/README.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# 树与森林
|
||||
|
||||
## 1. 树与二叉树的转换
|
||||
|
||||
- 树转二叉树:每个结点左指针指向它的第一个孩子结点,右指针指向它在树中相邻兄弟结点。
|
||||
- 二叉树转树:每个结点都指向他们的双亲结点。
|
||||
|
||||
## 2. 森林与二叉树的转换
|
||||
|
||||
- 森林转二叉树:将每一棵树转换为二叉树,将每棵二叉树的根依次作为上一棵二叉树的右子树。
|
||||
- 二叉树转森林
|
||||
|
||||
## 3. 树的遍历
|
||||
|
||||
按照某种方式访问树中的每个结点,且仅访问一次。
|
||||
|
||||
### 3.1. 先根遍历
|
||||
|
||||
若树非空,则先访问根结点,再按从左到右的顺序遍历根结点的每棵子树。
|
||||
|
||||
**树的先根遍历序列与这棵树的对应二叉树的先序遍历序列相同。**
|
||||
|
||||

|
||||
|
||||
### 3.2. 后根遍历
|
||||
|
||||
若树非空,则先按从左到右的顺序遍历根结点的每棵子树,再访问根结点,
|
||||
|
||||
**树的后根遍历序列与这棵树的对应二叉树的中序遍历序列相同。**
|
||||
|
||||

|
||||
|
||||
### 3.3. 层次遍历
|
||||
|
||||
## 4. 森林的遍历
|
||||
|
||||
### 4.1. 先序遍历
|
||||
|
||||
若森林非空,则,
|
||||
|
||||
- 访问森林中第一棵树的根结点
|
||||
- 先序遍历第一棵树的子树森林
|
||||
- 先序遍历除去第一棵树之后剩余的树构成的子树森林
|
||||
|
||||
**森林的先序遍历序列与森林对应二叉树的先序遍历序列相同。**
|
||||
|
||||

|
||||
|
||||
### 4.2. 中序遍历
|
||||
|
||||
若森林非空,则,
|
||||
|
||||
- 中序遍历第一棵树的根结点的子树森林
|
||||
- 访问第一棵树的根结点
|
||||
- 中序遍历除去第一棵树之后剩余的树构成的子树森林
|
||||
|
||||
**森林的中序遍历序列与森林对应二叉树的中序遍历序列相同。**
|
||||
|
||||

|
||||
BIN
ch5/tree-traversal/forest-inorder-traversal.png
Normal file
|
After Width: | Height: | Size: 390 KiB |
BIN
ch5/tree-traversal/forest-preorder-traversal.png
Normal file
|
After Width: | Height: | Size: 395 KiB |
BIN
ch5/tree-traversal/tree-postorder-traversal.png
Normal file
|
After Width: | Height: | Size: 482 KiB |
BIN
ch5/tree-traversal/tree-preorder-traversal.png
Normal file
|
After Width: | Height: | Size: 484 KiB |