C++で二分木における単一値の部分木を数える方法
二分木が与えられたとき、その木に含まれる「単一値の部分木(Single Valued Subtree)」の個数を求めるのが本記事の目的です。単一値の部分木とは、その部分木を構成するすべてのノードが同じ値を持つような部分木のことを指します。
問題の例
例として、次のような二分木を考えてみましょう。

この木には、以下に示す4つの単一値の部分木が存在します。

解法のアプローチ:ボトムアップ方式
この問題は、ボトムアップ(下から上へ)の再帰的なアプローチで効率的に解くことができます。基本的な考え方は次のとおりです。
- 各ノードを訪問する際、そのノードを根とする部分木が単一値であるかどうかを判定し、単一値であればカウンタを1増やします。
- 再帰呼び出しの結果として真偽値を返し、その戻り値を使って左右の子部分木が単一値かどうかを判断します。
- カウント用の変数は、参照渡し(リファレンスパラメータ)として再帰関数に渡すことで、再帰全体で共有できるようにします。
判定条件
あるノードを根とする部分木が単一値であるためには、次の条件をすべて満たす必要があります。
- 左の子部分木が単一値である(存在しない場合は常に真)。
- 右の子部分木が単一値である(存在しない場合は常に真)。
- 左の子が存在する場合、その値が現在のノードの値と一致している。
- 右の子が存在する場合、その値が現在のノードの値と一致している。
C++による実装例
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* left, *right;
};
Node* getNode(int data) {
Node* newNode = new Node;
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
bool countSingleValuedSubtree(Node* root, int &count) {
if (root == NULL)
return true;
bool left = countSingleValuedSubtree(root->left, count);
bool right = countSingleValuedSubtree(root->right, count);
if (left == false || right == false)
return false;
if (root->left && root->data != root->left->data)
return false;
if (root->right && root->data != root->right->data)
return false;
count++;
return true;
}
int countSingleValSubtree(Node* root) {
int count = 0;
countSingleValuedSubtree(root, count);
return count;
}
int main() {
Node* root = getNode(5);
root->left = getNode(1);
root->right = getNode(5);
root->left->left = getNode(5);
root->left->right = getNode(5);
root->right->right = getNode(5);
cout << "Count of Single Valued Subtrees is: " << countSingleValSubtree(root);
}実行結果
Count of Single Valued Subtrees is: 4
計算量について
このアルゴリズムは木の各ノードを一度だけ訪問するため、時間計算量は O(n) となります。ここで n は木のノード総数です。また、再帰呼び出しによるスタック領域を使用するため、空間計算量は木の高さに依存し、最悪の場合(木が線形に偏っている場合)は O(n)、バランスの取れた木の場合は O(log n) となります。
-
C++で二分木の2つのノード間の距離を求める方法
問題の概要いくつかのノードを持つ二分木が与えられているとします。このとき、2つのノード u と v の間の「距離」、つまり一方のノードからもう一方のノードへ移動する際に通る辺(エッジ)の本数を求めることを考えます。例として、次のような二分木を扱います。 1 / \ 2 3 / \ / \ 4 5 6 7 \ 8この木において、ノード (4, 6) 間の距離は 4(経路:4 → 2 → 1 → 3 → 6)、ノード (5, 8) 間の
-
C++で二分木内の重複するサブツリーをすべて検出する方法
問題の概要二分木が与えられたとき、その中に重複するサブツリー(部分木)が存在するかどうかを判定する問題を考えてみましょう。例として、次のような二分木を取り上げます。この木には、サイズ2の同一のサブツリーが2つ存在します。さらに、それぞれのサブツリー内のDに注目すると、BDとBEもまた重複するサブツリーになっています。解決のアプローチ:木のシリアライズとハッシュこの問題は、木のシリアライズ(直列化)とハッシュテーブルを組み合わせることで効率的に解決できます。基本的な考え方は以下のとおりです。各サブツリーを間順走査(inorder traversal)で文字列としてシリアライズする空のノードには開