C++で値がxのリーフノード(葉ノード)を削除する方法
C++で値がxの葉ノードを削除するには?
本記事では、C++を使って二分木から「値がxと等しい葉ノード(リーフノード)」を削除する方法を解説します。ノード構造体の定義から、ノード生成用の関数、再帰的な削除処理、そして結果の表示まで、順を追って見ていきましょう。
1. ツリーノード構造体の定義
まず、ノードのデータと左右の子ノードへのポインタを保持する、木のノードを表す構造体を定義します。最初に作成されるノードはルートノードとなり、それ以降に作成されるノードは子ノードとして扱われます。
struct Node {
int data;
struct Node *leftChild, *rightChild;
};
2. 新しいノードを作成するnewNode関数
次に、int型の値を受け取り、それをノードのdataメンバに代入するnewNode(int data)関数を作成します。この関数は生成したNode構造体へのポインタを返し、新しく作成されたノードの左右の子はNULLに初期化されます。
struct Node* newNode(int data){
struct Node* newNode = new Node;
newNode->data = data;
newNode->leftChild = newNode->rightChild = NULL;
return (newNode);
}
3. 葉ノードを削除するdeleteLeafNode関数
続いて、ルートノードと削除対象の値xを受け取るdeleteLeafNode(Node* root, int x)関数を作成します。この関数は再帰的に木をたどり、「値がxであり、かつ左右どちらの子も持たないノード(=葉ノード)」を削除します。子ノードが削除された結果、親ノードが新たな葉になり、その値もxであれば、親ノードも連鎖的に削除されます。関数は、削除処理後の木のルートノードを返します。
Node* deleteLeafNode(Node* root, int x){
if (root == NULL)
return nullptr;
root->leftChild = deleteLeafNode(root->leftChild, x);
root->rightChild = deleteLeafNode(root->rightChild, x);
if (root->data == x && root->leftChild == NULL && root->rightChild == NULL)
return nullptr;
return root;
}
4. 木の内容を表示するinorder関数
最後に、削除後の木の状態を確認するためのinorder(Node* root)関数を用意します。この関数は木を再帰的にたどりながら各ノードの値を出力します。なお、この実装は「左部分木→右部分木→根」の順で訪問するため、厳密には後順走査(postorder)に相当します。
void inorder(Node* root){
if (root != NULL){
inorder(root->leftChild);
inorder(root->rightChild);
cout << root->data << " ";
}
}
サンプルコード(完全版)
以下は、値がxと等しい葉ノードを削除する処理全体をまとめた実装例です。この例では、ルート4の下に左子2・右子12が接続され、さらに2の下に3と5、12の下に9がぶら下がっています。deleteNode(root, 3)を呼び出すことで、値3の葉ノードのみが削除されます。
#include <iostream>
using namespace std;
struct Node {
int data;
struct Node *leftChild, *rightChild;
};
struct Node* newNode(int data){
struct Node* newNode = new Node;
newNode->data = data;
newNode->leftChild = newNode->rightChild = NULL;
return (newNode);
}
Node* deleteNode(Node* root, int x){
if (root == NULL)
return nullptr;
root->leftChild = deleteNode(root->leftChild, x);
root->rightChild = deleteNode(root->rightChild, x);
if (root->data == x && root->leftChild == NULL &&
root->rightChild == NULL)
return nullptr;
return root;
}
void inorder(Node* root){
if (root != NULL){
inorder(root->leftChild);
inorder(root->rightChild);
cout << root->data << " ";
}
}
int main(void){
struct Node* root = newNode(4);
root->leftChild = newNode(2);
root->rightChild = newNode(12);
root->leftChild->leftChild = newNode(3);
root->leftChild->rightChild = newNode(5);
root->rightChild->rightChild = newNode(9);
deleteNode(root, 3);
cout << "Inorder traversal after deletion : ";
inorder(root);
return 0;
}
実行結果
上記のコードをコンパイルして実行すると、次の出力が得られます。
Inorder traversal after deletion : 5 2 9 12 4
出力から、値3の葉ノードが正しく削除され、残りのノード(5, 2, 9, 12, 4)だけが出力されていることが確認できます。
まとめ
このように、再帰を使えば「値がxの葉ノードの削除」をシンプルに実装できます。ポイントは、左右の子に対する再帰呼び出しの結果を親ノードのポインタに代入し直すことで、削除されたノードへの参照を自動的に切り離せる点です。計算量は木のノード数に比例するO(n)となります。
-
C++の二分探索木(BST)で最小値のノードを見つける方法
二分探索木(Binary Search Tree、BST)が与えられたとき、その木の中から最小の要素を見つけることを考えます。例えば、以下のようなBSTがあるとします。この場合、最小要素は 1 になります。考え方二分探索木の重要な性質として、左部分木には必ず親ノードより小さい値が格納されるというものがあります。この性質を利用すると、次の手順で最小要素を見つけることができます。ルートノードから探索を開始します。現在のノードの左の子が NULL でない間、左の子へ移動を繰り返します。左の子が NULL になったノードの値が、木全体の中で最小の要素です。この操作の計算量は木の高さに依存し、平衡な二分
-
C++でXとの絶対差が最小となるノードを見つける方法
問題の概要木構造と各ノードの重み、そして整数 x が与えられたとき、|weight[i] − x| の値が最小となるノード i を見つける問題を考えてみましょう。例えば、下図のような木があり、x = 15 とします。この場合、出力は 3 となります。各ノードについて絶対差を計算すると、以下のようになります。ノード 1:|5 − 15| = 10ノード 2:|10 − 15| = 5ノード 3:|11 − 15| = 4ノード 4:|8 − 15| = 7ノード 5:|6 − 15| = 9絶対差が最小となるのはノード 3 の「4」であるため、答えは 3 です。アルゴリズムの考え方アプローチは非