[데이터 구조] 트리 및 이진 트리(25): 주어진 노드의 아버지에 대한 트리 검색(알고리즘 FindFather)

기사 디렉토리

  • 5.3.1 트리 저장 구조
    • 5. 왼쪽 아들과 오른쪽 형제 링크 구조
  • 5.3.2 노드 획득 알고리즘
    • 1. 장남, 장남 노드 획득
    • 2. 주어진 노드의 부모 검색
      • a. 알고리즘 FindFather
      • b. 알고리즘 분석
      • c. 코드 구현
    • 3. 코드 통합

5.3.1 트리 저장 구조

5. 왼쪽 아들과 오른쪽 형제 링크 구조

[데이터 구조] 트리 및 이진 트리(19): 트리의 저장 구조 - 왼쪽 아들, 오른쪽 형제 링크 구조(트리, 포리스트 및 이진 트리의 변환)
  왼쪽 son, right 형제 링크 구조는 각 노드의 세 필드(FirstChild, Data, NextBrother)를 사용하여 트리를 구성하면서 트리가 이진 트리의 속성을 갖도록 만듭니다. 구체적으로 각 노드에는 다음 정보가 포함됩니다.

  1. FirstChild: 이 노드의 장남(가장 왼쪽 하위 노드)에 대한 포인터를 저장합니다. 이 포인터를 사용하면 노드의 첫 번째 하위 노드를 빠르게 찾을 수 있습니다.
  2. 데이터: 노드 데이터를 저장합니다.
  3. 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)입니다.

  1. 먼저 결과 포인터를 null로 설정합니다.
  2. t가 비어 있거나 p가 비어 있거나 p가 t와 같으면 직접 반환합니다.
  3. 포인터 q를 t의 첫 번째 자식 노드를 가리킵니다.
  4. q가 비어 있지 않은 한 루프를 입력합니다.
    • q가 p와 같다면 p의 상위 노드가 발견되고 결과 포인터가 t를 가리킨 다음 반환된다는 의미입니다.
    • 그렇지 않으면 FindFather 함수를 재귀적으로 호출하여 매개변수 q 및 p를 전달하고 결과를 result에 저장합니다.
    • 결과가 비어 있지 않으면 상위 노드를 찾아서 직접 반환한다는 의미입니다.
    • 포인터 q를 q의 다음 형제 노드로 업데이트합니다.
  5. 루프가 끝날 때까지 상위 노드를 찾지 못한 경우 결과는 여전히 비어 있습니다.

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;
}

여기에 이미지 설명을 삽입하세요.

추천

출처blog.csdn.net/m0_63834988/article/details/134678334