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

C++でn分木(N-aryツリー)をミラー反転する方法


問題の概要

各ノードが可変個の子ノードを持つ木(n分木)が与えられたとき、その木をミラー(左右反転した木)に変換する方法を解説します。ミラー化とは、各ノードの子ノードの並び順を左右逆にすることを指します。

ミラー化の例

例として、次のようなn分木を考えます。

C++でn分木(N-aryツリー)をミラー反転する方法

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

C++でn分木(N-aryツリー)をミラー反転する方法

アルゴリズムの考え方

ミラー化は再帰を使うとシンプルに実装できます。手順は以下のとおりです。

手順

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)(再帰呼び出しのスタックと、出力用のキューが主な要因です)


  1. C++で再帰を使わずにN分木を先行順走査(プレオーダートラバーサル)する方法

    はじめに本記事では、N分木(N-ary Tree)が与えられたときに、その先行順走査(プレオーダートラバーサル)の結果を出力する問題を扱います。ポイントは、再帰呼び出しを使わずにスタックだけで実装するところです。基本用語の確認N分木(N-ary Tree)とは、すべてのノードが最大N個の子ノードを持つことができる木構造のことです。たとえば2分木(バイナリツリー)は、各ノードが最大2つの子ノードを持ちます。先行順走査(Preorder Traversal)は、木のノードを巡回する方法の1つで、まずルートノードを訪問し、その後、子ノードを左から順に訪問していきます。問題例次のようなN分木を考えてみ

  2. 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 解説 − 辺配列をもとに木を構築すると、次のような構造になります。 この