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

C++で値kの葉ノード(リーフノード)を削除する方法

C++で二分木を扱う際、「特定の値kを持つ葉ノード(リーフノード)だけを削除したい」というケースがあります。本記事では、再帰処理を活用して値kの葉ノードを削除する方法を、サンプルコードとともにわかりやすく解説します。

1. ノード構造体の定義

まず、データと左右の子ノードへのポインタを保持する、ツリーノードを表す構造体を定義します。最初に生成したノードがルートノードとなり、それ以降に生成されるノードは子ノードとして扱われます。

struct Node {
    int data;
    struct Node *leftChild, *rightChild;
};

2. 新しいノードを生成する関数

次に、newNode(int data) 関数を作成します。この関数は引数として受け取った 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. 値kの葉ノードを削除する関数

続いて、本体となる deleteLeafNode(Node* root, int k) 関数です。この関数はルートノードと、削除したいノードの値 k を引数として受け取ります。処理の流れは以下のとおりです。

  • ノードが NULL の場合は、そのまま nullptr を返します。
  • 左右の子に対して再帰的に同じ関数を呼び出し、葉に近いノードから順に削除処理を行います。
  • 「ノードの値が k と一致し、かつ左右どちらの子も持たない」場合にのみ、そのノードを削除します(nullptr を返すことで親からの参照を切ります)。
  • 最後に、削除処理を反映したルートノードを返します。
Node* deleteLeafNode(Node* root, int k) {
    if (root == NULL)
        return nullptr;
    root->leftChild = deleteLeafNode(root->leftChild, k);
    root->rightChild = deleteLeafNode(root->rightChild, k);
    if (root->data == k && root->leftChild == NULL &&
        root->rightChild == NULL)
        return nullptr;
    return root;
}

ここでのポイントは、この関数が削除するのは「値が k の葉ノードのみ」という点です。子を持つ内部ノードは、たとえ値が k であっても削除されません。ただし、子ノードが削除された結果として親が葉になり、その値も k であれば、親も同時に削除されます。

4. 木を走査して表示する関数

削除後の木の状態を確認するため、inorder(Node* root) 関数を用意します。この関数は再帰的に木をたどり、左の子 → 右の子 → 自分自身の順で各ノードの値を出力します。

void inorder(Node* root){
    if (root != NULL){
        inorder(root->leftChild);
        inorder(root->rightChild);
        cout << root->data << " ";
    }
}

実装例

それでは、値 k を持つ葉ノードを削除するプログラム全体を見てみましょう。

#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* deleteLeafNode(Node* root, int k){
    if (root == NULL)
        return nullptr;
    root->leftChild = deleteLeafNode(root->leftChild, k);
    root->rightChild = deleteLeafNode(root->rightChild, k);
    if (root->data == k && 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(6);
    root->leftChild = newNode(7);
    root->rightChild = newNode(7);
    root->leftChild->leftChild = newNode(5);
    root->leftChild->rightChild = newNode(3);
    root->rightChild->rightChild = newNode(7);

    deleteLeafNode(root, 7);

    cout << "Inorder traversal after deleting given leaf node: ";
    inorder(root);

    return 0;
}

このサンプルでは、値 7 を持つノードを複数含む二分木を構築しています。削除対象になるのは「葉ノードである 7」だけであり、子を持つノード(左側の 7)は値が同じでも残る点に注目してください。

出力結果

上記のコードを実行すると、次の出力が得られます。

Inorder traversal after deleting given leaf node: 5 3 7 6

出力を見ると、値 7 の葉ノードが正しく削除され、残りのノード(5、3、7、6)だけが出力されていることが確認できます。

  1. C++の二分探索木(BST)で最小値のノードを見つける方法

    二分探索木(Binary Search Tree、BST)が与えられたとき、その木の中から最小の要素を見つけることを考えます。例えば、以下のようなBSTがあるとします。この場合、最小要素は 1 になります。考え方二分探索木の重要な性質として、左部分木には必ず親ノードより小さい値が格納されるというものがあります。この性質を利用すると、次の手順で最小要素を見つけることができます。ルートノードから探索を開始します。現在のノードの左の子が NULL でない間、左の子へ移動を繰り返します。左の子が NULL になったノードの値が、木全体の中で最小の要素です。この操作の計算量は木の高さに依存し、平衡な二分

  2. 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 です。アルゴリズムの考え方アプローチは非