기사 디렉토리
- 5.3.1 트리 저장 구조
-
- 5. 왼쪽 아들과 오른쪽 형제 링크 구조
- 5.3.2 노드 획득 알고리즘
-
- 1. 장남, 장남 노드 획득
- 2. 주어진 노드의 부모 검색
-
- a. 알고리즘 FindFather
- b. 알고리즘 분석
- c. 코드 구현
- 3. 코드 통합
5.3.1 트리 저장 구조
5. 왼쪽 아들과 오른쪽 형제 링크 구조
[데이터 구조] 트리 및 이진 트리(19): 트리의 저장 구조 - 왼쪽 아들, 오른쪽 형제 링크 구조(트리, 포리스트 및 이진 트리의 변환)
왼쪽 son, right 형제 링크 구조는 각 노드의 세 필드(FirstChild, Data, NextBrother)를 사용하여 트리를 구성하면서 트리가 이진 트리의 속성을 갖도록 만듭니다. 구체적으로 각 노드에는 다음 정보가 포함됩니다.
- FirstChild: 이 노드의 장남(가장 왼쪽 하위 노드)에 대한 포인터를 저장합니다. 이 포인터를 사용하면 노드의 첫 번째 하위 노드를 빠르게 찾을 수 있습니다.
- 데이터: 노드 데이터를 저장합니다.
- NextBrother: 노드의 가장 큰 형제(동일 레이어의 오른쪽 형제 노드)에 대한 포인터를 저장합니다. 이 포인터를 사용하면 동일한 레이어에 있는 노드의 다음 형제 노드를 빠르게 찾을 수 있습니다.
이 구조를 통해 전체 트리는 왼쪽 아들과 오른쪽 형제 링크 구조를 사용하여 이진 트리로 표현될 수 있습니다. 이 표현은 때때로 이진 트리, 이진 트리 포리스트 등과 같은 일부 특수 트리 구조에서 사용됩니다. 이 구조의 장점 중 하나는 형제 관계를 나타내기 위해 추가 포인터가 필요하지 않고 트리를 보다 간결하게 표현한다는 것입니다.
A
/|\
B C D
/ \
E F
A
|
B -- C -- D
|
E -- F
지금 바로:
A
/
B
\
C
/ \
E D
\
F
5.3.2 노드 획득 알고리즘
1. 장남, 장남 노드 획득
[데이터 구조] 트리 및 이진 트리(20): 트리가 장남 및 장남 노드를 얻기 위한 알고리즘(GFC, GNB)
2. 주어진 노드의 부모 검색
- 재귀적 사고
- 주어진 노드는 주어진 노드가 특정 노드(예: p)에 대한 포인터임을 의미합니다.
- 반환 값은 노드 p의 부모를 가리키는 포인터여야 합니다(찾을 수 없으면 null).
a. 알고리즘 FindFather
b. 알고리즘 분석
알고리즘 FindFather는 루트 우선 탐색과 유사하게 t를 루트 포인터로 하여 트리에서 포인터 p가 가리키는 노드의 부모 노드를 검색하며 시간 복잡도는 O(n)입니다.
- 먼저 결과 포인터를 null로 설정합니다.
- t가 비어 있거나 p가 비어 있거나 p가 t와 같으면 직접 반환합니다.
- 포인터 q를 t의 첫 번째 자식 노드를 가리킵니다.
- q가 비어 있지 않은 한 루프를 입력합니다.
- q가 p와 같다면 p의 상위 노드가 발견되고 결과 포인터가 t를 가리킨 다음 반환된다는 의미입니다.
- 그렇지 않으면 FindFather 함수를 재귀적으로 호출하여 매개변수 q 및 p를 전달하고 결과를 result에 저장합니다.
- 결과가 비어 있지 않으면 상위 노드를 찾아서 직접 반환한다는 의미입니다.
- 포인터 q를 q의 다음 형제 노드로 업데이트합니다.
- 루프가 끝날 때까지 상위 노드를 찾지 못한 경우 결과는 여전히 비어 있습니다.
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;
}