♥删除二叉排序树结点的代码实现♥

对于一个二叉排序树,要删除其某个结点,重点要找到两个关键结点(自身与父结点),代码实现如下:

#include<iostream>
#include<string>
using namespace std;

class Node{
public:
    int value;
    Node *left,*right;
    int countt=1;
    Node(int value){
        this->value=value;
        left = nullptr;
        right = nullptr;
    }
    /**往二叉树里面插入结点**/
    void addNode(Node *node){
        if(node == nullptr){
            return;
        }
        /**如果插入的结点的值小于当前结点的值,
         * 则该插入的结点应该往左走**/
        if(node->value<this->value){
           if(this->left == nullptr){
               this->left=node;
           } else{
               this->left->addNode(node);
           }
        }else{
            if(this->right == nullptr){
                this->right=node;
            }else{
                this->right->addNode(node);
            }
        }
    }
    /**中序遍历,结点值从小到大输出**/
    void midShow(Node *node){
        if(node == nullptr){
            return;
        }
        midShow(node->left);
        cout<<node->value<<" ";
        midShow(node->right);
    }
    /**传入值,搜索整棵树中对应的结点,返回结点,如果找不到,返回空**/
    Node* searchNode(int value){
        //找到直接返回当前结点的值
        if(this->value==value){
            return this;
        }else if(value<this->value){ //要搜索的值小于当前结点的值,向左子树中进行查找
            if(left==nullptr){//左子树为空,说明找不到
                return nullptr;
            }
            left->countt=this->countt+1;
            return left->searchNode(value);//非空,递归查找
        }else{// 同理,要搜索的值大于当前结点的值,向右子树中进行查找
            if(right==nullptr){
                return nullptr;
            }
            right->countt=this->countt+1;
            return right->searchNode(value);
        }
    }
    /**查找对应结点的父亲结点**/
    Node* searchParentsNode(int value){
        //如果当前结点的左孩子或者右孩子等于查找值,说明当前结点即为该查找值的父亲结点
        if((this->left!=nullptr&&this->left->value==value)||(this->right!=nullptr&&this->right->value==value)){
            return this;
        }else{
            // 如果查找值小于当前值,同时当前值的左孩子非空
            if(value<this->value&&this->left!=nullptr){
                //到左子树中查找
                return this->left->searchParentsNode(value);
            }else if(value>this->value&&this->right!=nullptr){
                //到右子树中查找
                return this->right->searchParentsNode(value);
            }else{
                //当前值既不等于查找值,也没有孩子结点,说明查找失败,返回空
                return nullptr;
            }
        }
    }
};

//binary sort tree
class BST{
    Node *root;
public:
    /**往二叉排序树中加入结点**/
    void add(Node *node){
        if(root==nullptr){
            root=node;
        }else{
            root->addNode(node);
        }
    }
    /**中序遍历二叉排序树**/
    void InOrder() {
        if (root != nullptr) {
            root->midShow(root);
        }
    }
    /**在二叉排序树中查找**/
    Node* search(int value) {
        if (root == nullptr) {
            return nullptr;
        } else {
            return root->searchNode(value);
        }
    }
    /**在二叉排序树中查找该值的父亲结点,并返回**/
    Node* searchParent(int value) {
        if (root == nullptr) {
            return nullptr;
        } else {
            return root->searchParentsNode(value);
        }
    }
    /**删除某个结点的右子树中值最小的结点,并返回该值**/
    int deleteMin(Node* node){
        Node* target = node;
        while (target->left != nullptr) {//右子树中最小值必然是其最下层的左孩子
            target = target->left;
        }
        // 该最小值结点可能是叶子结点,也可能有右孩子,但delete函数已经考虑了这两种情况了,
        // 所以可以直接调用。(但不可能有左孩子,因为其是最小的)
        deleteNode(target->value);
        return target->value;
    }
    /**删除结点**/
    void deleteNode(int value){
        if(root==nullptr){
            return;
        }else{
            //查找要删除的结点
            Node* target=search(value);
            if(target == nullptr){
                return;
            }
            //查找父亲结点
            Node* parent=searchParent(value);
            //如果目标结点没有孩子,可直接将该结点删除
            if(target->left==nullptr&&target->right==nullptr){
                //如果目标结点没有孩子,可直接将该结点删除
                if(parent->left->value==value){
                    parent->left=nullptr;
                }else{
                    parent->right=nullptr;
                }
                // 如果目标结点既有左孩子,又有右孩子,需要在目标结点的右孩子中找到一个最小值,
                // 将目标结点删除后,替代目标结点的位置。
            }else if(target->left!=nullptr&&target->right!=nullptr){
                //删除右子树中的最小值,同时获得该值
                int min=deleteMin(target->right);
                // 将要删除的结点的值改为最小值
                target->value = min;
                //如果目标结点只有一个孩子,只需让目标结点的该孩子顶替目标结点
            }else{
                //如果目标结点有的只是左孩子
                if(target->left!=nullptr){
                    //判断目标结点是其父亲结点的左孩子还是右孩子
                    if (parent->left->value == value) {
                        parent->left = target->left;
                    } else {
                        parent->right = target->left;
                    }
                }else{
                    if (parent->left->value == value) {
                        //直接覆盖旧结点,那么该新结点后面左右子树其实也会跟过来
                        parent->left = target->right;
                    } else {
                        //直接覆盖旧结点,那么该新结点后面左右子树其实也会跟过来
                        //所以不用担心target结点的左、右结点是否还带其他结点
                        parent->right = target->right;
                    }
                }
            }
        }
    }
};

int main(){
    int t;
    cin>>t;
    while(t--){
        BST* bst=new BST();
        int n;
        cin>>n;
        //构建二叉排序树
        while(n--){
            int val;
            cin>>val;
            bst->add(new Node(val));
        }
        bst->InOrder();
        cout<<endl;

        //删除多少个结点
        cin>>n;
        while(n--){
            int val;
            cin>>val;
            bst->deleteNode(val);
            bst->InOrder();
            cout<<endl;
        }
    }
    return 0;
}

看删除的函数,以及搜索对应删除结点及其父结点的方法,输入输出不用过多理会。

我是花花,祝自己也祝您变强了~

Guess you like

Origin blog.csdn.net/m0_52711790/article/details/120904568