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

C++で二分木を上下逆さまに反転する方法を解説

すべての右側のノードが「兄弟を持つ葉ノード」であるか「空」であるような二分木が与えられます。この木を上下逆さまに反転し、元の右側のノードが左の葉ノードになるような新しい木へと変換します。最後に、新しい木のルートノードを返す必要があります。

問題の例

入力が [1,2,3,4,5] の場合、

C++で二分木を上下逆さまに反転する方法を解説

出力は [4,5,2,#,#,3,1] という構造を持つ二分木のルートになります。

C++で二分木を上下逆さまに反転する方法を解説

解法のアプローチ

この問題は、再帰的な処理によって解くことができます。木を走査しながら各ノードの左右のポインタを付け替えていく手法を用います。以下の手順で進めます。

  • solve() 関数を定義します。この関数は node(現在のノード)、par(親ノード)、sibling(兄弟ノード) の3つの引数を受け取ります。

  • node が存在しない場合は NULL を返します。

  • child 変数に node の左の子を保存します。

  • currSib 変数に node の右の子を保存します。

  • node の左の子に sibling を設定し、node の右の子に par を設定します。

  • child と currSib の両方が存在しない場合は、node をそのまま返します。

  • それ以外の場合は solve(child, node, currSib) の結果を返します。

メインの処理からは、solve(root, NULL, NULL) を呼び出してその結果を返します。

アルゴリズムのポイント

この手法では、木の左端の経路をたどりながら、各ノードに対して「左の子には元の兄弟を」「右の子には元の親を」設定していきます。これにより、木全体が上下反転した構造へと自然に変換されます。ポインタの付け替えを再帰の帰り道で行うため、余計なメモリ消費を抑えながら処理できるのが特徴です。

実装例

理解を深めるために、C++での実装例を見てみましょう。

#include <bits/stdc++.h>
using namespace std;
class TreeNode{
public:
   int val;
   TreeNode *left, *right;
   TreeNode(int data){
      val = data;
      left = NULL;
      right = NULL;
   }
};
void insert(TreeNode **root, int val){
   queue<TreeNode*> q;
   q.push(*root);
   while(q.size()){
      TreeNode *temp = q.front();
      q.pop();
      if(!temp->left){
         if(val != NULL)
            temp->left = new TreeNode(val);
         else
            temp->left = new TreeNode(0);
         return;
      }
      else{
         q.push(temp->left);
      }
      if(!temp->right){
         if(val != NULL)
            temp->right = new TreeNode(val);
         else
            temp->right = new TreeNode(0);
         return;
      }
      else{
         q.push(temp->right);
      }
   }
}
TreeNode *make_tree(vector<int> v){
   TreeNode *root = new TreeNode(v[0]);
   for(int i = 1; i<v.size(); i++){
      insert(&root, v[i]);
   }
   return root;
}
void inord(TreeNode *root){
   if(root != NULL){
      inord(root->left);
      cout << root->val << " ";
      inord(root->right);
   }
}
class Solution {
public:
   TreeNode* solve(TreeNode* node, TreeNode* par, TreeNode* sibling){
      if (!node || node->val == 0)
         return NULL;
      TreeNode* child = node->left;
      TreeNode* currSib = node->right;
      node->left = sibling;
      node->right = par;
      if (!child && !currSib)
         return node;
      return solve(child, node, currSib);
   }
   TreeNode* upsideDownBinaryTree(TreeNode* root) {
      return solve(root, NULL, NULL);
   }
};
main(){
   Solution ob;
   vector<int> v = {1,2,3,4,5};
   TreeNode *root = make_tree(v);
   inord(ob.upsideDownBinaryTree(root));
}

入力

[1,2,3,4,5]

出力

[4,5,2,null,null,3,1]
  1. C++で最大二分木を構築する方法:再帰アルゴリズムと実装例を解説

    最大二分木(Maximum Binary Tree)とは? ここでは、すべての要素が一意(重複なし)である整数配列が与えられたとします。この配列から構築される「最大二分木」は、以下のように定義されます。 根(ルート)には、配列内の最大値が格納されます。 左部分木は、最大値を基準に分割された左側の部分配列から構築された最大二分木です。 右部分木は、最大値を基準に分割された右側の部分配列から構築された最大二分木です。 この定義に従って最大二分木を構築します。たとえば、入力が [3,2,1,6,0,5] の場合、構築される木は次の図のようになります。 解き方のアプローチ この問題は、再帰的な

  2. C++で二分木を二分探索木(BST)へ変換する方法を解説

    二分木(Binary Tree)とは二分木とは、木構造の各ノードが最大で2つの子ノードを持つことができる特別な木構造です。これらの子ノードは、それぞれ「左の子ノード」と「右の子ノード」と呼ばれます。シンプルな二分木の例は以下の通りです。二分探索木(BST)とは二分探索木(BST)は、以下のルールに従う特別な木構造です。左の子ノードの値は、常に親ノードの値より小さい右の子ノードの値は、常に親ノードの値より大きいすべてのノードが、それぞれ独立して二分探索木の性質を満たす二分探索木(BST)の例は以下の通りです。二分探索木は、検索や最小値・最大値の探索といった操作の計算量を削減するために用いられるデ