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

C++で二分木の最小深度を求めるアルゴリズムと実装方法

この記事では、二分木が与えられたときに、その最小深度(Minimum Depth)を求める問題について解説します。

二分木とは、各ノードが最大で2つの子ノードを持つことができる特別な木構造のことです。そして、二分木の最小深度とは、ルートノードから最も近い葉ノードまでの最短経路の長さを指します。

問題の例

具体的な例を使って問題を理解しましょう。

入力

        5
       / \
      2   9
     / \
    5   1
   / \
  7   3

出力

2

この例では、ルートノード「5」から葉ノード「9」までの経路の長さが2であり、これが最小深度となります。

解法アプローチ1:再帰による探索

最も基本的な解法は、二分木を走査しながら高さを数える方法です。各非葉ノードに対して子ノードを再帰的に呼び出し、葉ノードに到達した時点で1を返します。

重要なポイントとして、片方の子しか存在しないノードの場合、存在しない側の子を0として扱うと誤った結果になるため、存在する側の子のみを再帰的に探索する必要があります。

実装コード

#include<bits/stdc++.h>
using namespace std;
struct Node {
    int data;
    struct Node* left, *right;
};
int findMinDepthBT(Node *currentNode) {
    if (currentNode == NULL)
        return 0;
    if (currentNode->left == NULL && currentNode->right == NULL)
        return 1;
    if (!currentNode->left)
        return findMinDepthBT(currentNode->right) + 1;
    if (!currentNode->right)
        return findMinDepthBT(currentNode->left) + 1;
    return min(findMinDepthBT(currentNode->left),
               findMinDepthBT(currentNode->right)) + 1;
}
Node *newNode(int data) {
    Node *temp = new Node;
    temp->data = data;
    temp->left = temp->right = NULL;
    return (temp);
}
int main() {
    Node *root = newNode(5);
    root->left = newNode(2);
    root->right = newNode(9);
    root->left->left = newNode(5);
    root->left->right = newNode(1);
    root->left->left->left = newNode(7);
    root->left->left->right = newNode(3);
    cout<<"The minimum depth of binary tree is "<<findMinDepthBT(root);
    return 0;
}

出力結果

The minimum depth of binary tree is 2

この再帰的なアプローチは十分に効率的ですが、より効果的に最小深度を求める他の走査手法もあります。

解法アプローチ2:レベル順走査(BFS)

もう一つの効率的なアプローチは、レベル順走査(幅優先探索・BFS)を利用する方法です。この手法では、木をレベルごと(上から順に)走査していき、最初に葉ノードに到達した時点でのレベル番号を返します。

幅優先探索では上のレベルから順に調べるため、最初に見つかった葉ノードが必ず最小深度のものとなり、木全体を走査せずに済むケースが多い点が利点です。

実装コード

#include<bits/stdc++.h>
using namespace std;
struct Node {
    int data;
    struct Node *left, *right;
};
struct lOrderQueue {
    Node *node;
    int depth;
};
int findMinDepthBT(Node *root) {
    if (root == NULL)
        return 0;
    queue<lOrderQueue> levelOrder;
    lOrderQueue deQueue = {root, 1};
    levelOrder.push(deQueue);
    while (levelOrder.empty() == false) {
        deQueue = levelOrder.front();
        levelOrder.pop();
        Node *node = deQueue.node;
        int depth = deQueue.depth;
        if (node->left == NULL && node->right == NULL)
            return depth;
        if (node->left != NULL) {
            deQueue.node = node->left;
            deQueue.depth = depth + 1;
            levelOrder.push(deQueue);
        }
        if (node->right != NULL) {
            deQueue.node = node->right;
            deQueue.depth = depth+1;
            levelOrder.push(deQueue);
        }
    }
    return 0;
}
Node* newNode(int data) {
    Node *temp = new Node;
    temp->data = data;
    temp->left = temp->right = NULL;
    return temp;
}
int main() {
    Node *root = newNode(5);
    root->left = newNode(2);
    root->right = newNode(9);
    root->left->left = newNode(5);
    root->left->right = newNode(1);
    root->left->left->left = newNode(7);
    root->left->left->right = newNode(3);
    cout<<"The minimum depth of binary tree is "<<findMinDepthBT(root);
    return 0;
}

出力結果

The minimum depth of binary tree is 2

まとめ

二分木の最小深度を求めるには、主に以下の2つのアプローチがあります。

  • 再帰(DFS)による方法: 実装がシンプルで直感的。計算量はO(N)。
  • レベル順走査(BFS)による方法: 最小深度の葉ノードが浅い位置にある場合、早期に探索を終了できるため効率的。

どちらの手法も時間計算量はO(N)ですが、木の形状によってはBFSの方が実際の処理量を抑えられる場合があります。用途に応じて適切な手法を選択しましょう。

  1. C++で二分木のルートから特定ノードまでの距離を求める方法

    二分木が与えられたとき、ルートから特定のノード u までの距離(経路の長さ)を求める問題を考えてみましょう。例として、次のような二分木を想定します。この木において、ルートからノード6までの距離は2、ルートからノード8までの距離は3となります。解決のアプローチこの問題は、再帰的な手法を用いて解くことができます。具体的には、目的のノードを左部分木と右部分木の両方に対して再帰的に探索し、再帰の各段階(レベル)で距離を1ずつ加算していきます。探索の仕組みは以下の通りです。現在のノードがNULLの場合は -1 を返します(ノードが見つからなかったことを示す)。現在のノードの値が目的の値と一致した場合、ま

  2. C++の二分探索木(BST)で最小値のノードを見つける方法

    二分探索木(Binary Search Tree、BST)が与えられたとき、その木の中から最小の要素を見つけることを考えます。例えば、以下のようなBSTがあるとします。この場合、最小要素は 1 になります。考え方二分探索木の重要な性質として、左部分木には必ず親ノードより小さい値が格納されるというものがあります。この性質を利用すると、次の手順で最小要素を見つけることができます。ルートノードから探索を開始します。現在のノードの左の子が NULL でない間、左の子へ移動を繰り返します。左の子が NULL になったノードの値が、木全体の中で最小の要素です。この操作の計算量は木の高さに依存し、平衡な二分