C : DS二叉排序树之删除(详细思路解答)

Description

给出一个数据序列,建立二叉排序树,并实现删除功能

对二叉排序树进行中序遍历,可以得到有序的数据序列

Input

第一行输入t,表示有t个数据序列

第二行输入n,表示首个序列包含n个数据

第三行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第四行输入m,表示要删除m个数据

从第五行起,输入m行,每行一个要删除的数据,都是自然数

以此类推输入下一个示例

Output

第一行输出有序的数据序列,对二叉排序树进行中序遍历可以得到

从第二行起,输出删除第m个数据后的有序序列,输出m行

以此类推输出下一个示例的结果

Sample

Hint

当删除数据不在序列中,那么删除操作等于不执行,所以输出序列不变化

分析:删除的节点有三种情况。

  1. 叶子节点,即没有左子树和右子树

  2. 只有右子树或者只有左子树

  3. 同时有左右子树

思路:

        创建deleteNode方法,deleteNode(BinaryTreeNode*& t, int deleteNumber),传入参数为根节点以及删除的值。

 值相等之后进行判断

第一个判断:

左子树为空(包含叶子节点的情况,左右子树同时为空,右子树为NULL,temp会保存NULL,最后t被替换成NULL,相当于删除了叶子节点)

第二个判断:

右子树为空,左子树不为空。操作同上

 第三个判断:

左右子树都不为空。先找到右子树上最小节点,于是用函数BinaryTreeNode* findMinNode(BinaryTreeNode* t)进行寻找,进入右子树之后,当前节点不存在左子树时即为最小值。t为当前要删除的节点,用右子树上最小节点值替换当前节点值。替换值完成后进入右子树,重新调用deleteNode删除掉右子树最小节点即完成替换。

 例如:

最关键的是要对二叉排序树的性质要熟悉,左子树上所有的值都小于根节点,右子树上所有的值都大于根节点。

AC代码:

#include <iostream>
using namespace std;

struct BinaryTreeNode {
    int data;
    BinaryTreeNode* left;
    BinaryTreeNode* right;
    BinaryTreeNode() {
        data = 0;
        left = NULL;
        right = NULL;
    }
};

class BinaryTree {
public:
    BinaryTreeNode* root;

    BinaryTree() {
        root = nullptr;
    }

    ~BinaryTree() {
        destroyTree(root);
    }

    void init(BinaryTreeNode*& t, int data) {
        if (t) {
            if (data > t->data && t->right) {
                init(t->right, data);
            }
            else if (data < t->data && t->left) {
                init(t->left, data);
            }
            else if (data == t->data) {
                return;
            }
            if (data > t->data && t->right == NULL) {
                BinaryTreeNode* newNode = new BinaryTreeNode;
                newNode->data = data;
                t->right = newNode;
            }
            else if (data < t->data && t->left == NULL) {
                BinaryTreeNode* newNode = new BinaryTreeNode;
                newNode->data = data;
                t->left = newNode;
            }
        }
        else {
            t = new BinaryTreeNode;
            t->data = data;
        }
    }

    void midTree(BinaryTreeNode* t) {
        if (t) {
            midTree(t->left);
            cout << t->data << " ";
            midTree(t->right);
        }
    }

    void deleteNode(BinaryTreeNode*& t, int deleteNumber) {
        if (t == nullptr) {
            return;
        }
        //通过删除值与当前节点值进行比较,进行递归处理,直到值相等。
        if (deleteNumber > t->data) {
            deleteNode(t->right, deleteNumber);
        }
        else if (deleteNumber < t->data) {
            deleteNode(t->left, deleteNumber);
        }
        else {
            if (t->left == nullptr) {//左子树为空(包含叶子节点的情况,左右子树同时为空,右子树为NULL,temp会保存NULL,最后t被替换成NULL,相当于删除了叶子节点)
                BinaryTreeNode* temp = t->right;//临时节点保存右子树
                delete t;//删除当前节点
                t = temp;//用右子树替换当前节点
            }
            else if (t->right == nullptr) {//右子树为空,左子树不为空。操作同上
                BinaryTreeNode* temp = t->left;
                delete t;
                t = temp;
            }
            else {//左右子树都不为空。
                //找到右子树上最小节点
                BinaryTreeNode* minNode = findMinNode(t->right);
                //t为当前要删除的节点,用右子树上最小节点值替换当前节点值。
                t->data = minNode->data;
                deleteNode(t->right, minNode->data);//然后进入右子树,删除掉右子树最小节点即完成替换。
            }
        }
    }

    BinaryTreeNode* findMinNode(BinaryTreeNode* t) {
        while (t->left != nullptr) {
            t = t->left;
        }
        return t;
    }

    void destroyTree(BinaryTreeNode* t) {
        if (t) {
            destroyTree(t->left);
            destroyTree(t->right);
            delete t;
        }
    }
};

int main() {
    int t;
    cin >> t;

    while (t--) {
        int n;
        cin >> n;
        BinaryTree p;
        while (n--) {
            int data;
            cin >> data;
            p.init(p.root, data);
        }
        p.midTree(p.root);
        cout << endl;

        int deleteTimes;
        cin >> deleteTimes;
        while (deleteTimes--) {
            int deleteNum;
            cin >> deleteNum;
            p.deleteNode(p.root, deleteNum);
            p.midTree(p.root);
            cout << endl;
        }
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值