C++で二分木のすべての右葉ノードの合計を求める3つの方法
問題概要
この記事では、C++ を使って二分木の中からすべての右葉ノード(親ノードの右側の子であり、かつ子ノードを持たないノード)を検出し、その値の合計を求める方法を解説します。
まず、具体例で問題を確認してみましょう。
入力:

出力: 8
説明:
この木の右葉ノードは 1 と 7 合計 = 1 + 7 = 8
上図の二分木では、ノード 4 の右の子である「1」と、ノード 6 の右の子である「7」が右葉ノードに該当します。したがって、合計は 1 + 7 = 8 となります。
解法1: 再帰によるアプローチ
最もシンプルな解決策は、木を根から葉へ向かって再帰的に走査する方法です。各ノードに対して、その右の子が葉ノードであるかどうかを判定し、右葉ノードであればその値を合計に加算します。木全体の走査が完了したら、合計値を返します。
サンプルプログラム
#include <iostream>
using namespace std;
struct Node{
int key;
struct Node* left, *right;
};
Node *newNode(int k){
Node *node = new Node;
node->key = k;
node->right = node->left = NULL;
return node;
}
bool isLeafNode(Node *node){
if (node == NULL)
return false;
if (node->left == NULL && node->right == NULL)
return true;
return false;
}
int findRightLeavesSum(Node *root){
int sum = 0;
if (root != NULL){
if (isLeafNode(root->right))
sum += root->right->key;
else
sum += findRightLeavesSum(root->right);
sum += findRightLeavesSum(root->left);
}
return sum;
}
int main(){
struct Node *root = newNode(5);
root->left = newNode(4);
root->right = newNode(6);
root->left->left = newNode(2);
root->left->right = newNode(1);
root->right->left = newNode(9);
root->right->right = newNode(7);
cout<<"The sum of right leaves of the tree is "<<findRightLeavesSum(root);
return 0;
}実行結果
The sum of right leaves of the tree is 8
解法2: スタックを使った反復処理(DFS)
次に、明示的なスタックを用いた深さ優先探索(DFS)による反復的なアプローチを紹介します。スタックからノードを取り出すたびに、その右の子が存在するかどうかを確認し、存在していてかつ葉ノードであれば、その値を合計に加算します。スタックが空になった時点で、合計を出力します。
サンプルプログラム
#include<bits/stdc++.h>
using namespace std;
struct Node{
int key; struct Node* left, *right;
};
Node *newNode(int k){
Node *node = new Node;
node->key = k;
node->right = node->left = NULL;
return node;
}
int findRightLeavesSum(Node* root){
if(root == NULL) return 0;
stack<Node*> treeNodes;
treeNodes.push(root); int sum = 0;
while(treeNodes.size() > 0){
Node* currentNode = treeNodes.top();
treeNodes.pop();
if (currentNode->right != NULL){
treeNodes.push(currentNode->right);
if(currentNode->right->right == NULL &&
currentNode->right->left == NULL){
sum += currentNode->right->key ;
}
}
if (currentNode->left != NULL)
treeNodes.push(currentNode->left);
}
return sum;
}
int main(){
Node *root = newNode(5);
root->left= newNode(4);
root->right = newNode(6);
root->left->left = newNode(2);
root->left->right = newNode(1);
root->right->left = newNode(9);
root->right->right= newNode(7);
cout<<"The sum of right leaves of the tree is "<<findRightLeavesSum(root);
return 0;
}実行結果
The sum of right leaves of the tree is 8
解法3: キューを使った幅優先探索(BFS)
3つ目のアプローチは、キューを用いた幅優先探索(BFS)です。キューには「ノードへのポインタ」と「そのノードが親の右側の子かどうかを示すフラグ」のペアを格納します。取り出したノードが葉であり、かつ右側の子である場合にのみ、その値を合計に加算します。走査が終了したら合計を出力します。
サンプルプログラム
#include<bits/stdc++.h>
using namespace std;
struct Node{
int key; struct Node* left, *right;
};
Node *newNode(int k){
Node *node = new Node;
node->key = k;
node->right = node->left = NULL;
return node;
}
int findRightLeavesSum(Node* root) {
if (root == NULL)
return 0;
queue<pair<Node*, bool> > treeNodes;
treeNodes.push({ root, 0 });
int sum = 0;
while (!treeNodes.empty()) {
Node* temp = treeNodes.front().first;
bool is_right_child = treeNodes.front().second;
treeNodes.pop();
if (!temp->left && !temp->right && is_right_child)
sum = sum + temp->key;
if (temp->left) {
treeNodes.push({ temp->left, 0 });
}
if (temp->right) {
treeNodes.push({ temp->right, 1 });
}
}
return sum;
}
int main(){
Node *root = newNode(5);
root->left= newNode(4);
root->right = newNode(6);
root->left->left = newNode(2);
root->left->right = newNode(1);
root->right->left = newNode(9);
root->right->right= newNode(7);
cout<<"The sum of right leaves of the tree is "<<findRightLeavesSum(root);
return 0;
}実行結果
The sum of right leaves of the tree is 8
まとめ
本記事では、二分木における右葉ノードの合計を求める3つの手法(再帰・DFS・BFS)を紹介しました。いずれの方法も時間計算量は O(n)、空間計算量は O(n) となります。再帰版はコードが簡潔で読みやすい反面、木が非常に深い場合はスタックオーバーフローのリスクがあります。一方、反復版(DFS・BFS)は明示的なデータ構造を使用するため、そのようなリスクを回避できます。状況に応じて最適な手法を選択してください。
-
C++で完全二分木の全ノードの合計を効率的に求める方法
問題の概要 正整数 L が与えられ、これは完全二分木(パーフェクト・バイナリツリー)のレベル数を表しているとします。この木の葉ノードには、1 から n までの番号が順に割り当てられています(n は葉ノードの総数)。また、各親ノードの値は、その 2 つの子ノードの値の合計となります。 今回の課題は、この完全二分木に含まれるすべてのノードの値の合計を出力するプログラムを作成することです。 例として、次のような木を考えてみましょう。 この木の場合、すべてのノードの合計は 30 になります。 解法のアプローチ この問題を注意深く観察すると、求めるべきは全ノードの値の総和です。葉ノードには 1 から
-
C++で二分木の子ノード合計プロパティを検証する方法
二分木が与えられたとき、次のプロパティ(性質)を満たしていれば、その二分木は有効とみなされます。各ノードのデータ値は、左の子ノードと右の子ノードの値の合計と一致していなければなりません。どちらかの側に子ノードが存在しない場合は、その値は0として扱われます。例えば、以下のような木が与えられた場合、このプロパティを満たしていることになります。この性質を確認するための特別なトリックは存在せず、木を再帰的に走査する必要があります。ノードとその両方の子がプロパティを満たしていればtrueを返し、そうでなければfalseを返します。アルゴリズムの流れ検証は以下の手順で行われます。ノードがNULL、または葉