Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

C言語で二分木の左側ビュー(Left View)を出力する方法を解説

この記事では、与えられた二分木(バイナリツリー)の左側ビュー(Left View)、すなわち木を左側から見たときに見えるノードを出力する方法を解説します。ユーザーがデータを挿入して二分木を構築し、その後、完成した木の左側ビューを表示するという流れです。

二分木の各ノードが持てる子は最大2つなので、プログラムは各ノードに紐づく左ポインタを優先的にたどる必要があります。

左ポインタがNULLでなければ、その先に子ノード(データ)が存在します。各レベルで最初に到達した最左ノードを出力対象とし、それを画面に表示します。

入力:1 0 3 2 4
出力:1 0 2

C言語で二分木の左側ビュー(Left View)を出力する方法を解説

図のオレンジ色のノードが、二分木の左側ビューに相当します。

この図では、データ1を持つノードがルートノードなので最初に出力されます。次に左の子へ移動して0を出力し、続いて右側のノード3へ移動して、その左の子である2を出力します。

この問題は、ノードのレベル(深さ)を記録しながら再帰的に木を走査するアプローチで解けます。各レベルで最初に訪れたノードだけを出力することで、左側ビューが得られます。

アルゴリズム

START
    Step 1 -> ノード用の構造体を作成
        int型の data を宣言
        ノード型ポインタ *left, *right を宣言
    Step 2 -> ノード挿入用関数を作成(引数:new_data)
        mallocでノード型の一時変数 temp を確保
        temp->data = new_data を設定
        temp->left = temp->right = NULL を設定
        temp を返す
    Step 3 -> 関数 void left_view(struct node* root, int level, int* highest_level) を宣言
        root が NULL なら
            終了
        *highest_level < level なら
            root->data を出力
            *highest_level = level を設定
        left_view(root->left, level + 1, highest_level) を再帰呼び出し
        left_view(root->right, level + 1, highest_level) を再帰呼び出し
    Step 4 -> 関数 void left(struct node* root) を宣言
        int highest_level = 0 を設定
        left_view(root, 1, &highest_level) を呼び出す
    Step 5 -> main() 内で
        struct node* root = New(1) としてルートノードを作成
        left(root) を呼び出す
STOP

C言語での実装例

#include <stdio.h>
#include <stdlib.h>
// ノードの構造体を定義
struct node {
    int data;
    struct node *left, *right; // ノードに接続された子ノードを指すポインタ
};
struct node* New(int new_data) {
    struct node* temp = (struct node*)malloc(sizeof(struct node));
    // ポインタに動的にメモリを割り当てる
    temp->data = new_data;
    temp->left = temp->right = NULL;
    return temp;
}
void left_view(struct node* root, int level, int* highest_level) {
    if (root == NULL) // ノードが存在しない=データがない場合
    return;
    // 木にルートノードしかない場合は、ルートノードをそのまま返す
    if (*highest_level < level) {
        printf("%d\t", root->data);
        *highest_level = level;
    }
    // 再帰呼び出し
    left_view(root->left, level + 1, highest_level);
    left_view(root->right, level + 1, highest_level);
}
void left(struct node* root) {
    int highest_level = 0;
    left_view(root, 1, &highest_level);
}
int main() {
    printf("left view of a binary tree is : ");
    struct node* root = New(1);
    root->left = New(0);
    root->right = New(3);
    root->right->left = New(2);
    root->right->right = New(4);
    left(root);
    return 0;
}

実行結果

上記のプログラムを実行すると、次の出力が得られます。

left view of a binary tree is : 1 0 2

動作のポイント

このアルゴリズムの鍵は highest_level 変数です。まだ出力していないレベルに初めて到達したときだけノードの値を表示し、そのレベル番号を記録します。左の子を先に再帰呼び出しするため、各レベルで最も左側のノードが最初に検出され、結果として左側ビューが得られます。計算量は全ノードを一度ずつ訪問するため O(n)、必要なメモリは再帰の深さに依存し、最悪ケースで O(n) となります。

  1. C++で二分木の各レベルのノードをソートして出力する方法

    この問題では、二分木が与えられ、各レベルに存在するすべてのノードを値の順序(ソート済み)で出力することが求められます。 まず、具体例を見ながら概念を理解していきましょう。 入力 − 出力 − 20 6 15 2 17 32 78 解決のアプローチ この問題を解くには、木の各レベルごとにノードの値をソートした状態で出力する必要があります。そのために、以下のデータ構造を利用します。 queue(キュー):幅優先探索(BFS)のようにノードをたどるために使用 priority_queue × 2つ:1つは「現在のレベル」の値を昇順で保持し、もう1つは「次のレベル」の値を一時的に保持するために使用

  2. Pythonで二分木の最小共通祖先(LCA)を求める方法

    二分木が与えられたとき、指定した2つのノードの最小共通祖先(Lowest Common Ancestor:LCA)を求める問題を考えてみましょう。ノード p と q の LCA とは、p と q の両方を子孫として持つノードの中で、最も深い位置にあるノードのことです。 例えば、二分木が [3,5,1,6,2,0,8,null,null,7,4] という形式で表されている場合、木の構造は次のようになります。 この場合、ノード 5 と ノード 1 の LCA は 3 となります。 解法のアプローチ この問題は、再帰を使って次の手順で解くことができます。 木が空(None)の場合は、None