已知一棵树的层次序列及每一个结点的度,编写算法构造此树的孩子兄弟链表
设立辅助数组存储新建树各节点的地址。
#define maxNodes 15
void releaseMemory(CSNode* node) {
if (node) {
releaseMemory(node->lchild); // 递归释放孩子节点内存
releaseMemory(node->rsibling); // 递归释放兄弟节点内存
delete node; // 释放当前节点的内存
}
}
void creatCSTree(CStree &T,DataType e[],int degree[],int n){
//e[]层次序列
CSNode *pointer=new CSNode[maxNodes];
int i,j,d,k=0;
for(i=0;i<n;i++){
pointer[i]->data=e[i];
pointer[i]->lchild=pointer[i]->rsibling=NUll;
}
for(i=0; i<n; i++){
d = degree[i]; // 获取当前节点i的子节点数(度)
if(d){ // 如果当前节点有子节点
k++; // 移动k到当前节点的第一个子节点的位置
pointer[i]->lchild = pointer[k]; // 设置当前节点的lchild指向其第一个子节点
for(j=2; j<=d; j++){ // 遍历除了第一个子节点以外的其他子节点
//完成了兄弟节点的链接
k++; // 移动k到下一个子节点
pointer[k-1]->rsibling = pointer[k]; // 将当前节点的前一个子节点的rsibling指向当前子节点
}
}
}
T=pointer[0];
releaseMemory(pointer);
}
### 代码段解析
```c
#define maxNodes 15
```
这行代码定义了一个常量 `maxNodes`,表示树中最大节点数目的上限。这对后续在函数中创建固定大小数组有用。
```c
void creatCSTree(CStree &T, DataType e[], int degree[], int n){
```
定义了函数 `creatCSTree`,接收四个参数:
- `T`:指向 CStree 结构的引用,将作为创建的树的根节点返回。
- `e[]`:层次序列,包含树中节点的数据。
- `degree[]`:每个节点的子节点数(度)。
- `n`:节点总数。
```c
CSNode *pointer = new CSNode[maxNodes];
```
创建一个动态数组 `pointer`,用于存储所有的树节点。每个节点都是 `CSNode` 类型的。
```c
int i, j, d, k=0;
```
定义几个整数变量用于控制循环和记录状态:`i` 和 `j` 作为循环计数器,`d` 用于存储当前节点的度数,`k` 用于跟踪当前处理的子节点的索引。
```c
for(i=0; i<n; i++){
pointer[i]->data = e[i];
pointer[i]->lchild = pointer[i]->rsibling = NULL;
}
```
初始化 `pointer` 数组,为每个节点设置数据和将子节点和兄弟节点指针初始化为 NULL。
```c
for(i=0; i<n; i++){
d = degree[i];
if(d){
k++;
pointer[i]->lchild = pointer[k];
for(j=2; j<=d; j++){
k++;
pointer[k-1]->rsibling = pointer[k];
}
}
}
```
对于每个节点,根据其度数 `d`,找到其所有子节点,并适当设置 `lchild` 和 `rsibling` 指针。如果节点有子节点(`d > 0`),则将第一个子节点设置为 `lchild`。随后,用循环连接所有的子节点为一条兄弟链表,使用 `rsibling` 指针。
```c
T = pointer[0];
```
设置树的根节点为数组中的第一个元素。
for(i=0; i<n; i++){
d = degree[i]; // 获取当前节点i的子节点数(度)
if(d){ // 如果当前节点有子节点
k++; // 移动k到当前节点的第一个子节点的位置
pointer[i]->lchild = pointer[k]; // 设置当前节点的lchild指向其第一个子节点
for(j=2; j<=d; j++){ // 遍历除了第一个子节点以外的其他子节点
k++; // 移动k到下一个子节点
pointer[k-1]->rsibling = pointer[k]; // 将当前节点的前一个子节点的rsibling指向当前子节点
}
}
}
这段代码中非常的妙,包含循环和条件逻辑,主要实现以下功能:
-
外层循环 (
for(i=0; i<n; i++)
): 遍历所有的节点,为每个节点配置其子节点的链接。 -
获取节点的度 (
d = degree[i]
): 这告诉我们每个节点有多少个子节点。 -
条件判断 (
if(d)
): 如果节点有一个或多个子节点,则执行内部代码。 -
设置第一个子节点 (
pointer[i]->lchild = pointer[k]
):pointer[i]
是当前正在处理的父节点。它的lchild
指向由k
索引的节点,即它的第一个子节点。 -
内层循环 (
for(j=2; j<=d; j++)
): 从第二个子节点开始,直到最后一个子节点。这个循环确保所有子节点之间通过rsibling
正确连接。在每次循环迭代中,k
自增以指向下一个子节点,并设置前一个子节点的rsibling
指向当前子节点。