C++でn分木(N-aryツリー)をミラー反転する方法
問題の概要
各ノードが可変個の子ノードを持つ木(n分木)が与えられたとき、その木をミラー(左右反転した木)に変換する方法を解説します。ミラー化とは、各ノードの子ノードの並び順を左右逆にすることを指します。
ミラー化の例
例として、次のようなn分木を考えます。

この木をミラー化すると、以下のように反転されます。

アルゴリズムの考え方
ミラー化は再帰を使うとシンプルに実装できます。手順は以下のとおりです。
手順
1. ノードがNULLの場合は何もせずに終了します。
2. 子ノードが1つ以下の場合、反転しても変化がないためそのまま返します。
3. 各子ノードに対して再帰的にミラー化を適用します。
4. 最後に、そのノードが持つ子ノードのリスト(vector)を反転します。
C++での実装例
以下は、木をレベル順(BFS)で出力する機能も含めた完全なサンプルコードです。
#include <bits/stdc++.h>
using namespace std;
struct node {
int data;
vector<node *>child;
};
node *newNode(int x) {
node *temp = new node;
temp->data = x;
return temp;
}
void mirrorTree(node * root) {
if (root == NULL) {
return;
}
int n = root->child.size();
if (n < 2) {
return;
}
for (int i = 0; i < n; i++) {
mirrorTree(root->child[i]);
}
reverse(root->child.begin(), root->child.end());
}
void printTree(node * root) {
if (root == NULL) {
return;
}
queue<node *>q;
q.push(root);
int level = 0;
while (!q.empty()) {
int n = q.size();
++level;
cout << "Level " << level << ": ";
while (n > 0) {
node * p = q.front();
q.pop();
cout << p->data << " ";
for (int i=0; i<p->child.size(); i++) {
q.push(p->child[i]);
}
n--;
}
cout << endl;
}
}
int main() {
node *root = newNode(20);
(root->child).push_back(newNode(10));
(root->child).push_back(newNode(15));
(root->child[0]->child).push_back(newNode(1));
(root->child[0]->child).push_back(newNode(2));
(root->child[0]->child).push_back(newNode(3));
(root->child[1]->child).push_back(newNode(4));
cout << "Tree traversal before mirroring\n";
printTree(root);
mirrorTree(root);
cout << "\nTree traversal after mirroring\n";
printTree(root);
return 0;
}
実行結果
上記のプログラムをコンパイルして実行すると、次のような出力が得られます。
Tree traversal before mirroring Level 1: 20 Level 2: 10 15 Level 3: 1 2 3 4 Tree traversal after mirroring Level 1: 20 Level 2: 15 10 Level 3: 4 3 2 1
出力を見ると、ミラー化によって各レベルの子ノードの並びが反転していることが確認できます(10 15 → 15 10、1 2 3 4 → 4 3 2 1)。
計算量
時間計算量: O(N)(Nは木のノード総数。各ノードを1度ずつ処理します)
空間計算量: O(N)(再帰呼び出しのスタックと、出力用のキューが主な要因です)
-
C++で再帰を使わずにN分木を先行順走査(プレオーダートラバーサル)する方法
はじめに本記事では、N分木(N-ary Tree)が与えられたときに、その先行順走査(プレオーダートラバーサル)の結果を出力する問題を扱います。ポイントは、再帰呼び出しを使わずにスタックだけで実装するところです。基本用語の確認N分木(N-ary Tree)とは、すべてのノードが最大N個の子ノードを持つことができる木構造のことです。たとえば2分木(バイナリツリー)は、各ノードが最大2つの子ノードを持ちます。先行順走査(Preorder Traversal)は、木のノードを巡回する方法の1つで、まずルートノードを訪問し、その後、子ノードを左から順に訪問していきます。問題例次のようなN分木を考えてみ
-
C++でDFSを使ってn分木のすべての葉ノードを出力する方法
問題の概要 この問題では、n分木(n-ary tree)の辺情報を格納した2次元配列が与えられます。配列の各要素は木の辺を表しており、この配列から構成されるn分木のすべての葉ノード(リーフノード)を出力することが求められます。 n分木とは、各ノードが最大でn個の子を持つことができる木構造のことです。つまり、あるノードは1個、2個……n個までの子ノードを持つ可能性があります。 入出力例 Input: edge[][] = {{5,8}, {5,6}, {8,1}, {8,4}, {6,7}} Output: 1 4 7 解説 − 辺配列をもとに木を構築すると、次のような構造になります。 この