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

C++で二分木の最小深度を求める方法を解説


二分木が与えられたとき、その木の最小深度(minimum depth)を求めることを考えます。最小深度とは、根ノードから最も近い葉ノードまでの最短経路に含まれるノード数のことです。

例えば、次のような二分木が入力として与えられた場合を考えてみましょう。

C++で二分木の最小深度を求める方法を解説

この場合、出力は 2 になります。これは、根ノード 3 から葉ノード 9 までの経路が最短だからです。

解決のためのアプローチ

この問題は、幅優先探索(BFS)を用いて各レベルを順番に調べることで効率的に解決できます。手順は以下の通りです。

  • ツリーノードを格納する配列 aa を定義し、その末尾に root を挿入します

  • 別の配列 ak を定義します

  • level := 0 と初期化します

  • root が NULL の場合は 0 を返します

  • aa のサイズが 0 でない間、以下を繰り返します

    • 配列 ak をクリアします

    • level を 1 増やします

    • aa 内のすべてのノード a に対して、以下を処理します

      • a の左の子と右の子が両方 NULL の場合(葉ノードに到達した場合)、level を返してループを抜けます

      • a の左の子が NULL でない場合、ak の末尾に追加します

      • a の右の子が NULL でない場合、ak の末尾に追加します

    • aa := ak として、次のレベルへ進みます

  • 最後に 0 を返します

この手法では、根に近いレベルから順にノードを調べていくため、最初に見つかった葉ノードのレベルがそのまま最小深度となります。全ノードを探索する必要がないため、再帰的な深さ優先探索(DFS)よりも効率的な場合が多いのが特徴です。

実装例

以下のC++コードを見ると、より理解が深まるでしょう。

#include <bits/stdc++.h>
using namespace std;
class TreeNode{
public:
   int val;
   TreeNode *left, *right;
   TreeNode(int data){
      val = data;
      left = NULL;
      right = NULL;
   }
};
void insert(TreeNode **root, int val){
   queue<TreeNode*> q;
   q.push(*root);
   while(q.size()){
      TreeNode *temp = q.front();
      q.pop();
      if(!temp->left){
         if(val != NULL)
            temp->left = new TreeNode(val);
         else
            temp->left = new TreeNode(0);
         return;
      }
      else{
         q.push(temp->left);
      }
      if(!temp->right){
         if(val != NULL)
            temp->right = new TreeNode(val);
         else
            temp->right = new TreeNode(0);
         return;
      }
      else{
         q.push(temp->right);
      }
   }
}
TreeNode *make_tree(vector<int> v){
   TreeNode *root = new TreeNode(v[0]);
   for(int i = 1; i<v.size(); i++){
      insert(&root, v[i]);
   }
   return root;
}
class Solution {
public:
   int minDepth(TreeNode* root) {
      vector<TreeNode*> aa;
      aa.push_back(root);
      vector<TreeNode*> ak;
      int level = 0;
      if (root == NULL || root->val == 0) {
         return 0;
      }
      while (aa.size() != 0) {
         ak.clear();
         level++;
         for (TreeNode* a : aa) {
            if ((a->left == NULL || a->left->val == 0)&& (a->right == NULL || a->right->val == 0)) {
               return level;
               break;
            }
            if (a->left != NULL) {
               ak.push_back(a->left);
            }
            if (a->right != NULL) {
               ak.push_back(a->right);
            }
         }
         aa = ak;
      }
      return 0;
   }
};
main(){
   Solution ob;
   vector<int> v = {3,9,20,NULL,NULL,15,7};
   TreeNode *root = make_tree(v);
   cout << (ob.minDepth(root));
}

入力

{3,9,20,NULL,NULL,15,7}

出力

2

この入力例では、根ノード 3 の子として 9 と 20 があり、ノード 9 が葉ノードです。したがって、根から最も近い葉までの経路は「3 → 9」となり、ノード数は 2 という結果になります。

  1. C++で最大二分木を構築する方法:再帰アルゴリズムと実装例を解説

    最大二分木(Maximum Binary Tree)とは? ここでは、すべての要素が一意(重複なし)である整数配列が与えられたとします。この配列から構築される「最大二分木」は、以下のように定義されます。 根(ルート)には、配列内の最大値が格納されます。 左部分木は、最大値を基準に分割された左側の部分配列から構築された最大二分木です。 右部分木は、最大値を基準に分割された右側の部分配列から構築された最大二分木です。 この定義に従って最大二分木を構築します。たとえば、入力が [3,2,1,6,0,5] の場合、構築される木は次の図のようになります。 解き方のアプローチ この問題は、再帰的な

  2. C++で二分木を二分探索木(BST)へ変換する方法を解説

    二分木(Binary Tree)とは二分木とは、木構造の各ノードが最大で2つの子ノードを持つことができる特別な木構造です。これらの子ノードは、それぞれ「左の子ノード」と「右の子ノード」と呼ばれます。シンプルな二分木の例は以下の通りです。二分探索木(BST)とは二分探索木(BST)は、以下のルールに従う特別な木構造です。左の子ノードの値は、常に親ノードの値より小さい右の子ノードの値は、常に親ノードの値より大きいすべてのノードが、それぞれ独立して二分探索木の性質を満たす二分探索木(BST)の例は以下の通りです。二分探索木は、検索や最小値・最大値の探索といった操作の計算量を削減するために用いられるデ