C++で二分木における最長の葉から葉へのパスを出力するプログラム
このチュートリアルでは、与えられた二分木(binary tree)において、ある葉ノードから別の葉ノードまでの最長パスを出力するプログラムについて解説します。
言い換えると、二分木の直径(diameter)に含まれるすべてのノードを出力することが目的です。ここでいう直径(または幅)とは、ある端のノードからもう一方の端のノードまでの最長パス上に存在するノードの数として定義されます。
解決のアプローチ
この問題は、以下の手順で解くことができます。
- 高さ関数による直径の計算: 各ノードに対して「左部分木の高さ + 右部分木の高さ + 1」を評価し、これが現在の最大値より大きければ、そのノードを直径の中間ノードとして記録します。
- 左側の最長パスを探索: 記録した中間ノードの左部分木内で、指定された長さに一致する葉までのパスを見つけます。
- 右側の最長パスを探索: 同様に右部分木内でも最長パスを見つけます。
- 結果の出力: 左部分木のノード → 根ノード → 右部分木のノード の順に出力することで、直径上のすべてのノードが表示されます。
プログラム例
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data;
Node *left, *right;
};
struct Node* create_node(int data){
struct Node* node = new Node;
node->data = data;
node->left = node->right = NULL;
return (node);
}
int tree_height(Node* root, int& ans, Node*(&k), int& lh, int& rh, int& f){
if (root == NULL)
return 0;
int left_tree_height = tree_height(root->left, ans, k, lh, rh, f);
int right_tree_height = tree_height(root->right, ans, k, lh, rh, f);
if (ans < 1 + left_tree_height + right_tree_height){
ans = 1 + left_tree_height + right_tree_height;
k = root;
lh = left_tree_height;
rh = right_tree_height;
}
return 1 + max(left_tree_height, right_tree_height);
}
void print_roottonode(int ints[], int len, int f){
int i;
if (f == 0){
for (i = len - 1; i >= 0; i--) {
printf("%d ", ints[i]);
}
}
else if (f == 1) {
for (i = 0; i < len; i++) {
printf("%d ", ints[i]);
}
}
}
void print_pathr(Node* node, int path[], int pathLen, int max, int& f){
if (node == NULL)
return;
path[pathLen] = node->data;
pathLen++;
if (node->left == NULL && node->right == NULL) {
if (pathLen == max && (f == 0 || f == 1)) {
print_roottonode(path, pathLen, f);
f = 2;
}
}
else {
print_pathr(node->left, path, pathLen, max, f);
print_pathr(node->right, path, pathLen, max, f);
}
}
void calc_diameter(Node* root){
if (root == NULL)
return;
int ans = INT_MIN, lh = 0, rh = 0;
int f = 0;
Node* k;
int tree_height_of_tree = tree_height(root, ans, k, lh, rh, f);
int lPath[100], pathlen = 0;
print_pathr(k->left, lPath, pathlen, lh, f);
printf("%d ", k->data);
int rPath[100];
f = 1;
print_pathr(k->right, rPath, pathlen, rh, f);
}
int main(){
struct Node* root = create_node(12);
root->left = create_node(22);
root->right = create_node(33);
root->left->left = create_node(45);
root->left->right = create_node(57);
root->left->right->left = create_node(26);
root->left->right->right = create_node(76);
root->left->left->right = create_node(84);
root->left->left->right->left = create_node(97);
calc_diameter(root);
return 0;
}
コードのポイント
tree_height()関数は再帰的に各ノードの左右の高さを求めながら、同時に最大の直径とその中間ノードkを更新します。print_pathr()関数は、中間ノードから葉までのパスを配列に記録し、長さが一致した時点で出力を行います。- フラグ変数
fを使うことで、左側のパスは逆順(葉→根方向)、右側のパスは正順(根→葉方向)に出力され、全体として一本の連続した経路になります。
出力
97 84 45 22 57 26
このように、直径に相当する「97 → 84 → 45 → 22 → 57 → 26」という最長の葉から葉へのパスが出力されます。
-
【C++】二分木内の任意の2つのノード間のパスを出力する方法
はじめに 本記事では、C++プログラミングにおいて二分木(バイナリツリー)内の任意の2つのノード間のパス(経路)を出力する方法を解説します。 前提として、すべてのノードが互いに異なる値を持つ二分木が与えられ、その中から指定した2つのノードをつなぐ経路を出力することを目標とします。 例として、次のような二分木を考えます。 具体例: ノード140からノード211までの経路を出力したい場合、期待される出力は以下の通りです。 Output: 140->3->10->211 解決のアプローチ 基本的なアイデアは、「ルートノードから目的の2つのノードそれぞれへの経路」を求め、それらを
-
C++で二分木の根から葉への最短経路を出力する方法|BFS(幅優先探索)による実装
問題の概要二分木が与えられたとき、根(ルート)から葉(リーフ)に至る複数の経路の中から、最も短い経路を見つけ出して出力するプログラムを作成します。木は左から右へと走査するため、同じ深さの最短経路が複数存在する場合は、左側にある最初に走査された最短経路を出力します。この問題は、キュー(queue)を使ったレベル順走査(幅優先探索・BFS)で各レベルを順にたどることで解くことができます。BFSは浅い階層から順に探索を進めるため、最初に見つかった葉への経路が、すなわち根から葉への最短経路となります。上図の二分木では、根から葉への経路として以下のものが考えられます。10 -> 3(すべての経路の