文章目录
- 5.3.1 树的存储结构
- 5. 左儿子右兄弟链接结构
- 5.3.2 获取结点的算法
- 1. 获取大儿子、大兄弟结点
- 2. 搜索给定结点的父亲
- a. 算法FindFather
- b. 算法解析
- c. 代码实现
- 3. 代码整合
5.3.1 树的存储结构
5. 左儿子右兄弟链接结构
【数据结构】树与二叉树(十九):树的存储结构——左儿子右兄弟链接结构(树、森林与二叉树的转化)
左儿子右兄弟链接结构通过使用每个节点的三个域(FirstChild、Data、NextBrother)来构建一棵树,同时使得树具有二叉树的性质。具体来说,每个节点包含以下信息:
- FirstChild: 存放指向该节点的大儿子(最左边的子节点)的指针。这个指针使得我们可以迅速找到一个节点的第一个子节点。
- Data: 存放节点的数据。
- NextBrother: 存放指向该节点的大兄弟(同一层中右边的兄弟节点)的指针。这个指针使得我们可以在同一层中迅速找到节点的下一个兄弟节点。
通过这样的结构,整棵树可以用左儿子右兄弟链接结构表示成一棵二叉树。这种表示方式有时候被用于一些特殊的树结构,例如二叉树、二叉树的森林等。这种结构的优点之一是它更紧凑地表示树,而不需要额外的指针来表示兄弟关系。
A
/|\
B C D
/ \
E F
A
|
B -- C -- D
|
E -- F
即:
A
/
B
\
C
/ \
E D
\
F
5.3.2 获取结点的算法
1. 获取大儿子、大兄弟结点
【数据结构】树与二叉树(二十):树获取大儿子、大兄弟结点的算法(GFC、GNB)
2. 搜索给定结点的父亲
- 递归思想
- 给定结点是指给定的是一个指向某个结点的指针(比如p)。
- 返回值也应该是指针,指向结点p之父亲的指针(找不到时为空)。
a. 算法FindFather
b. 算法解析
算法FindFather在以t为根指针的树中搜索指针p所指节点的父节点,类似先根遍历,其时间复杂度为O(n) 。
- 首先,将result指针设置为空。
- 如果t为空或者p为空,或者p等于t,那么直接返回。
- 将指针q指向t的第一个子节点。
- 进入一个循环,只要q不为空:
- 如果q等于p,表示找到了p的父节点,将result指针指向t,然后返回。
- 否则,递归调用FindFather函数,传入参数q和p,并将结果存储在result中。
- 如果result不为空,表示已经找到了父节点,直接返回。
- 将指针q更新为q的下一个兄弟节点。
- 如果循环结束仍然没有找到父节点,那么result仍然为空。
c. 代码实现
void FindFather(TreeNode* t, TreeNode* p, TreeNode** result) {
*result = NULL;
if (t == NULL || p == NULL || p == t) {
return;
}
TreeNode* q = t->firstChild;
while (q != NULL) {
if (q == p) {
*result = t;
return;
}
FindFather(q, p, result);
if (*result != NULL) {
return;
}
q = q->nextBrother;
}
}
递归流程概述:
- 如果树为空或者给定结点为空或者给定结点是根节点,则根据定义返回NULL
q
指向根结点的左儿子结点,进入循环- 如果给定结点是根结点的左儿子,则根节点就是其父亲
- 在左儿子子树中递归查找
- …………
- 如果找到了父节点,直接返回
- 没有找到,则
q
更新为左儿子的右兄弟(即下一个个子结点)- 继续循环递归查找…………
3. 代码整合
#include <stdio.h>
#include <stdlib.h>
// 定义树节点
typedef struct TreeNode {
char data;
struct TreeNode* firstChild;
struct TreeNode* nextBrother;
} TreeNode;
// 创建树节点
TreeNode* createNode(char data) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
if (newNode != NULL) {
newNode->data = data;
newNode->firstChild = NULL;
newNode->nextBrother = NULL;
}
return newNode;
}
// 释放树节点及其子树
void freeTree(TreeNode* root) {
if (root != NULL) {
freeTree(root->firstChild);
freeTree(root->nextBrother);
free(root);
}
}
// 算法 FindFather
void FindFather(TreeNode* t, TreeNode* p, TreeNode** result) {
*result = NULL;
if (t == NULL || p == NULL || p == t) {
return;
}
TreeNode* q = t->firstChild;
while (q != NULL) {
if (q == p) {
*result = t;
return;
}
FindFather(q, p, result);
if (*result != NULL) {
return;
}
q = q->nextBrother;
}
}
int main() {
// 构建左儿子右兄弟链接结构的树
TreeNode* A = createNode('A');
TreeNode* B = createNode('B');
TreeNode* C = createNode('C');
TreeNode* D = createNode('D');
TreeNode* E = createNode('E');
TreeNode* F = createNode('F');
A->firstChild = B;
B->nextBrother = C;
C->nextBrother = D;
C->firstChild = E;
E->nextBrother = F;
// // 层次遍历算法
// printf("Level Order: \n");
// LevelOrder(A);
// printf("\n");
// 要查找父亲的节点
TreeNode* targetNode = E;
TreeNode* result = NULL;
// 使用算法 FindFather 查找父亲
FindFather(A, targetNode, &result);
// 输出结果
if (result != NULL) {
printf("The father of %c is %c\n", targetNode->data, result->data);
} else {
printf("Node not found or it is the root.\n");
}
// 释放树节点
freeTree(A);
return 0;
}