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

C++で二分木がレベルごとにソートされているかどうかを判定する方法

この記事では、二分木(バイナリツリー)がレベルごとにソートされているかどうかを確認する方法を解説します。レベルごとにソートされた二分木とは、次のような構造を持つ木のことです。

各レベル内では、ノードが左から右に向かって昇順に並んでおり、さらに下のレベル(層)ほど、その上のレベルより大きな値を持つという特徴があります。

アルゴリズムの考え方

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

1. レベル順走査を実行しながら、現在のレベルの最小値と最大値を記録します。
2. 別の変数 prevMax を用意し、直前のレベルの最大値を保持します。
3. 現在のレベルの最小値と prevMax を比較します。最小値が prevMax より大きければ、木はそこまでのレベルで正しくソートされていることになります。
4. 比較後、prevMax を現在のレベルの最大値で更新し、次のレベルへ進みます。
5. すべてのレベルの走査が完了するまでこの処理を繰り返します。

途中で「現在のレベルの最小値 ≤ 前のレベルの最大値」となる箇所が見つかった場合は、その時点で false を返し、木はレベルごとにソートされていないと判定できます。

C++での実装例

#include <iostream>
#include <queue>
using namespace std;
class Node {
    public:
    int key;
    Node *left, *right;
};
Node* getNode(int key) {
    Node* newNode = new Node;
    newNode->key = key;
    newNode->left = newNode->right = NULL;
    return newNode;
}
bool isLevelWiseSorted(Node* root) {
    int prevMax = INT_MIN;
    int min_val, max_val;
    int levelSize;
    queue<Node*> q;
    q.push(root);
    while (!q.empty()) {
        levelSize = q.size();
        min_val = INT_MAX;
        max_val = INT_MIN;
        while (levelSize > 0) {
            root = q.front();
            q.pop();
            levelSize--;
            min_val = min(min_val, root->key);
            max_val = max(max_val, root->key);
            if (root->left)
            q.push(root->left);
            if (root->right)
            q.push(root->right);
        }
        if (min_val <= prevMax)
            return false;
        prevMax = max_val;
    }
    return true;
}
int main() {
    Node* root = getNode(1);
    root->left = getNode(2);
    root->right = getNode(3);
    root->left->left = getNode(4);
    root->left->right = getNode(5);
    root->right->left = getNode(6);
    root->right->right = getNode(7);
    if (isLevelWiseSorted(root))
        cout << "Tree is levelwise Sorted";
    else
        cout << "Tree is Not levelwise sorted";
}

実行結果

Tree is level wise Sorted

コードのポイント

この実装では、キュー(std::queue)を使用してレベル順走査を実現しています。各ループの開始時にキューに入っている要素数(levelSize)を取得することで、「同じレベルのノードだけをまとめて処理する」ことが可能になります。計算量はノード数を N とした場合 O(N)、空間計算量も最悪ケースで O(N) となり、非常に効率的なアルゴリズムです。

  1. C++で二分木がSumTree(総和木)かどうかを判定する方法

    ここでは、与えられた二分木が「SumTree(総和木)」であるかどうかを判定する方法を解説します。まずは、SumTreeとはどのような木なのかを確認しておきましょう。 SumTreeとは SumTreeとは、すべての内部ノードが「左の子と右の子の値の合計」を保持する特殊な二分木です。木の根(ルート)には、それより下位に存在する全要素の合計値が格納されます。なお、葉ノードのみからなる木や空の木も、定義上はSumTreeとみなされます。以下はSumTreeの一例です。 例えば上図の木では、根の値26が左部分木(10 + 4 + 6 = 20)と右部分木(3 + 3 = 6)の合計と一致しており

  2. C++で二分木が別の二分木の部分木(サブツリー)であるかを判定する方法

    はじめに二つの二分木が与えられたとき、小さい方の木がもう一方の二分木の部分木(サブツリー)として含まれているかどうかを判定する方法を解説します。例として、以下のような二つの木を考えてみましょう。この場合、2番目の木は1番目の木の部分木となっています。判定アルゴリズムの考え方この性質を確認するためには、大きい方の木を後順走査(post-order traversal)でたどり、各ノードを根とする部分木が2番目の木と完全に一致するかどうかを順番に調べます。一致する部分木が一つでも見つかれば、2番目の木は1番目の木の部分木であると判定できます。判定の流れは以下の通りです。1. 部分木側がNULLであ