数据结构与算法C++之二分搜索树的删除节点,删除任意节点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/majinlei121/article/details/84147159

上篇博客介绍了怎样删除二分搜索树的最大值和最小值节点,下面介绍怎样删除树的任意一个节点
上篇删除最大值节点的操作,其实删除的节点要么没有左右子节点,要么只可能有左节点,
同样,删除最小值节点的操作,其实删除的节点要么没有左右子节点,要么只可能有右节点

(1)删除只有左节点的节点,如删除节点58,只需要将58删除掉,然后将其左节点50替换其位置即可
在这里插入图片描述

(2)删除只有右节点的节点,如删除节点58,只需要将58删除掉,然后将其右节点60替换其位置即可
在这里插入图片描述
(3)删除既有左节点又有右节点的节点是最复杂的操作,在1962年,Hibbard提出了一种删除方法,称为 Habbard Deletion,如下图所示,如果需要删除既有左节点又有右节点的节点58(称为d),那么需要找出58的右节点中最小的那个节点s,那么s就是节点59,将节点59放到58的位置即可
在这里插入图片描述
具体操作步骤为,首先删除掉s节点,然后将s节点的右节点指向原来d的右节点60,将s的左节点指向原来d的左节点50
在这里插入图片描述
最后就可以彻底删除节点58了,将节点59作为新的在该位置的节点
在这里插入图片描述
下面是删除节点的程序实现

#include <iostream>
#include <vector>
#include <string>
#include <ctime>  //time()函数
#include <queue>
#include <cassert>
#include "FileOps.h"
using namespace std;

template<typename Key, typename Value>
class BST{

private:
    struct Node{
        Key key;
        Value value;
        Node *left;
        Node *right;

        Node(Key key, Value value){
            this->key = key;
            this->value = value;
            this->left = this->right = NULL;
        }

        Node(Node *node){
            this->key = node->key;
            this->value = node->value;
            this->left = node->left;
            this->right = node->right;
        }
    };

    Node *root;
    int count;

public:
    BST(){
        root = NULL;
        count = 0;
    }
    ~BST(){
        // TODO: ~BST()
        destroy(root);
    }

    int size(){
        return count;
    }

    bool isEmpty(){
        return count == 0;
    }

    void insert(Key key, Value value){

        root = insert(root, key, value);
    }

    bool contain(Key key){

        return contain(root, key);
    }

    Value *search(Key key){

        return search(root, key);
    }

    //前序遍历
    void preOrder(){
        preOrder(root);
    }

    //中序遍历
    void inOrder(){
        inOrder(root);
    }

    //后序遍历
    void postOrder(){
        postOrder(root);
    }

    //层序遍历
    void levelOrder(){

        quene<Node*> q;
        q.push(root);
        while( !q.empty() ){

            Node *node = q.front();
            q.pop();

            cout<<node->key<<endl;
            if (node->left)
                q.push(node->left);
            if (node->right)
                q.push(node->right);
        }
    }

    //寻找最小的键值
    Key minimum(){
        assert(count != 0);
        Node* minNode = minimum(root);
        return minNode->key;
    }

    //寻找最大的键值
    Key maximum(){
        assert(count != 0);
        Node* maxNode = maximum(root);
        return maxNode->key;
    }

    //从二叉树中删除最小值所在节点
    void removeMin(){
        if (root)
            root = removeMin(root);
    }

    //从二叉树中删除最大值所在节点
    void removeMax(){
        if (root)
            root = removeMax(root);
    }

    //从二叉树中删除键值为key的节点
    void remove(Key key){
        root = remove(root, key);
    }



private:
    //向以node为根的二叉搜索树中,插入节点(key, value)
    //返回插入新节点后的二叉搜索树的根
    //递归插入
    Node* insert(Node *node, Key key, Value value){

        if (node == NULL){
            count++;
            return new Node(key, value);
        }

        if(node->key == key)
            node->value = value;
        else if (key < node->key)
            node->left = insert(node->left, key, value);
        else
            node->right = insert(node->right, key, value);

        return node;
    }

    //查找以node为根的二叉搜索树中是否包含键值为key的节点
    bool contain(Node *node, Key key){

        if (node == NULL){
            return false;
        }

        if (key == node->key)
            return true;
        else if (key < node->key)
            return contain(node->left, key);
        else
            return contain(node->right, key);
    }

    //在以node为根的二叉搜索树中查找key对应的value
    Value* search(Node *node, Key key){

        if (node == NULL)
            return NULL;

        if (key == node->key)
            return &(node->value);
        else if (key < node->key)
            return search(node->left, key);
        else
            return search(node->right, key);
    }

    //对以node为根的二叉搜索树进行前序遍历
    void preOrder(Node* node){
        if (node != NULL){
            cout<<node->key<<endl;
            preOrder(node->left);
            preOrder(node->right);
        }
    }

    //对以node为根的二叉搜索树进行中序遍历
    void inOrder(Node *node){
        if (node != NULL){
            inOrder(node->left);
            cout<<node->key<<endl;
            inOrder(node->right);

        }
    }

    //对以node为根的二叉搜索树进行后序遍历
    void postOrder(Node *node){
        if(node != NULL){
            postOrder(node->left);
            postOrder(node->right);
            cout<<node->key<<endl;
        }
    }

    void destroy(Node *node){
        if (node != NULL){
            destroy(node->left);
            destroy(node->right);

            delete node;
            count--;
        }
    }

    //在以node为根的二叉搜索树中,返回最小键值的节点
    Node* minimum(Node *node){
        if (node->left == NULL)
            return node;

        return minimum(node->left);
    }

    //在以node为根的二叉搜索树中,返回最大键值的节点
    Node* maximum(Node *node){
        if (node->right == NULL)
            return node;

        return maximum(node->right);
    }

    //删除掉以node为根的二分搜索树中的最小节点
    //返回删除节点后新的二分搜索树的根
    Node* removeMin(Node* node){

        if (node->left == NULL){

            Node *rightNode = node->right;
            delete node;
            count--;
            return rightNode;
        }
        node->left = removeMin(node->left);
        return node;
    }

    //删除掉以node为根的二分搜索树中的最大节点
    //返回删除节点后新的二分搜索树的根
    Node* removeMax(Node* node){

        if (node->right == NULL){

            Node *leftNode = node->left;
            delete node;
            count--;
            return leftNode;
        }
        node->right = removeMin(node->right);
        return node;
    }

    //删除掉以node为根的二分搜索树中键值为key的节点
    //返回删除节点后新的二分搜索树的根
    Node* remove(Node *node, Key key){
        if(node == NULL)
            return NULL;
        if (key < node->key){
            node->left = remove(node->left, key);
            return node;
        }
        else if (key > node->key){
            node->right = remove(node->right, key);
            return node;
        }
        else{ // key == node->key
            if (node->left == NULL){
                Node *rightNode = node->right;
                delete node;
                count--;
                return rightNode;
            }

            if (node->right == NULL){
                Node *leftNode = node->left;
                delete node;
                count--;
                return leftNode;
            }

            // node->left != NULL && node->right != NULL
            //Node *delNode = node;
            Node *successor = new Node(minimum(node->right));
            count++;

            successor->right = removeMin(node->right);
            successor->left = node->left;

            //delete delNode;
            delete node;
            count--;

            return successor;
        }
    }

};

上面删除既有左节点又有右节点的节点时,使用的是该节点后驱59替代该节点,其实也可以用该节点的前驱53替代该节点。如下图所示
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/majinlei121/article/details/84147159
今日推荐