[データ構造] ツリーとバイナリ ツリー (25): 指定されたノードの父親をツリー検索します (アルゴリズム FindFather)

記事ディレクトリ

  • 5.3.1 ツリーストレージ構造
    • 5. 左息子と右兄弟のリンク構造
  • 5.3.2 ノード取得アルゴリズム
    • 1.長男ノードと長兄ノードを取得する
    • 2. 指定されたノードの親を検索します
      • a. アルゴリズム FindFather
      • b. アルゴリズム分析
      • c. コードの実装
    • 3. コードの統合

5.3.1 ツリーストレージ構造

5. 左息子と右兄弟のリンク構造

[データ構造] ツリーと二分木 (19): ツリーの記憶構造 - 左息子、右兄弟リンク構造 (ツリー、フォレスト、二分木の変換)
  左息子、右 兄弟リンク構造は、各ノードの 3 つのフィールド (FirstChild、Data、NextBrother) を使用してツリーを構築し、ツリーにバイナリ ツリーのプロパティを持たせます。具体的には、各ノードには次の情報が含まれます。

  1. FirstChild: このノードの長男 (左端の子ノード) へのポインタを格納します。このポインターを使用すると、ノードの最初の子ノードをすばやく見つけることができます。
  2. データ: にはノード データが保存されます。
  3. NextBrother: ノードの一番上の兄弟 (同じレイヤー内の右の兄弟ノード) へのポインタを格納します。このポインターを使用すると、同じレイヤー内のノードの次の兄弟ノードをすばやく見つけることができます。

  この構造により、木全体を左子・右兄弟リンク構造を用いた二分木として表現することができます。この表現は、バイナリ ツリー、バイナリ ツリー フォレストなどの一部の特殊なツリー構造で使用されることがあります。この構造の利点の 1 つは、兄弟関係を表すための追加のポインターを必要とせずに、ツリーをよりコンパクトに表現できることです。
ここに画像の説明を挿入します

   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