C++で2つの二分木が同じかどうかを判定する方法(Same Tree問題)
2つの二分木が与えられたとき、それらが「同じ」であるかどうかを判定する関数を定義することを考えます。二分木が同じとみなされるのは、構造が完全に一致し、かつすべての対応するノードの値が等しい場合です。
例えば、入力が [1,2,3] と [1,2,3] の場合、両木は構造も値も一致しているため、出力は True になります。
解法のアプローチ
この問題は再帰を用いることで簡潔に解くことができます。以下の手順に従います。
isSameTreeという関数を定義します。この関数は2つの木のノード p と q を引数として受け取ります。- p と q がどちらも NULL の場合は、両木ともそこにノードが存在しないことを意味するため、true を返します。
- p または q のどちらか一方だけが NULL の場合は、構造が異なることを意味するため、false を返します。
- p の値と q の値が等しく、かつ
isSameTree(pの左部分木, qの左部分木)が true、さらにisSameTree(pの右部分木, qの右部分木)も true である場合は、true を返します。 - 上記のいずれの条件も満たさない場合は、false を返します。
このように、根ノード同士を比較しながら左右の部分木に対して再帰的に同じ処理を適用していくことで、木全体の一致性を効率的に判定できます。
実装例
それでは、実際の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;
}
class Solution {
public:
bool isSameTree(TreeNode *p, TreeNode* q){
if (p == NULL && q == NULL)
return true;
if (p == NULL || q == NULL)
return false;
if (p->val == q->val && isSameTree(p->left, q->left) && isSameTree(p->right, q->right))
return true;
return false;
}
};
main(){
Solution ob;
vector<int> v = {1,2,3}, v1 = {1,2,3};
TreeNode *root1 = make_tree(v);
TreeNode *root2 = make_tree(v1);
cout << (ob.isSameTree(root1, root2));
}入力
{1,2,3}, {1,2,3}出力
1
出力の 1 は true(真)を表しています。つまり、2つの二分木は構造的にも値的にも完全に一致しているため、「同じ木」であると判定されたことになります。
-
C++で木の直径を求めるアルゴリズムを解説
木の直径とは無向木(undirected tree)が与えられたとき、その直径を求めることを考えます。木の直径とは、木の中で最も長い経路に含まれる辺の数のことです。ここでは、木は辺のリストとして与えられます。edges[i] = [u, v] は、ノードuとノードvをつなぐ双方向の辺を表します。また、各ノードには {0, 1, ..., edges.length} の集合からラベルが割り当てられています。例として、次のような木を考えてみましょう。この場合、最も長い経路の長さは4となるため、出力は4になります。解法のアプローチ木の直径を効率的に求めるには、DFS(深さ優先探索)を2回実行するとい
-
C++で二分木を剪定する:1を含まない部分木を削除する再帰アルゴリズム
問題概要二分木のルートノード root が与えられ、すべてのノードの値は 0 または 1 のいずれかであるとします。この木から、1 を含まないすべての部分木を削除した結果の木を求めるのが目的です。たとえば、次のような木が与えられた場合 −解決のためのアプローチこの問題は、再帰的な手法を用いて以下の手順で解決できます −ノードを引数として受け取る再帰メソッド solve() を定義します。処理の流れは次のとおりです −ノードが null の場合は、null を返しますノードの左の子に対して solve(左の子) を実行し、その結果を左の子に代入しますノードの右の子に対して solve(右の子)