二叉搜索树删除操作的递归与非递归写法

如何进行删除操作

对于二叉搜索树的删除操作,主要分为以下3种情况讨论:

在这里插入图片描述

1、删除的结点没有左右孩子

2、删除的结点只有一个孩子

3、删除的结点有左右孩子

所以,我们将会用if…else…分为最多3种情况讨论(实际上只分了两种,因为情况1、2可以合并为一种情况)


删除操作的非递归写法

对于情况1、2:由于删除结点之后,有唯一(或nullptr)的结点来接手被删除的结点的位置(且该节点接手后不会破坏二叉搜索树),所以这两种情况的删除操作很容易实现

在这里插入图片描述

由于两边都为空的情况比较特殊,所以就做了一些处理:

将两边都为空的情况视为右孩子是nullptr,左孩子不确定 ,被删除的结点直接替换成左孩子(由于左孩子是nullptr,所以替换之后并无影响)

if (cur->_right == nullptr)//对于右孩子为空和左右孩子都为空的情况都会满足判断条件
{
    if (cur == _root)//对于根情况需要做额外判断
    {
        _root = cur->_left;
    }
    else if (parent->_left == cur)
    {
        parent->_left = cur->_left;
    }
    else
    {
        parent->_right = cur->_left;
    }
    delete cur;
    return true;
}
else if (cur->_left == nullptr)
{
    if (cur == _root)
    {
        _root = cur->_right;
    }
    else if (parent->_left == cur)
    {
        parent->_left = cur->_right;
    }
    else
    {
        parent->_right = cur->_right;
    }
    delete cur;
    return true;
}

对于情况3:由于删除结点之后,左右孩子(甚至其它结点)都有可能代替被删除结点,倘若直接替换,则会破坏该二叉搜索树。所以需要单独讨论

处理方法有两种,这里讨论其中一种

在这里插入图片描述

上图将5结点删除后,用x替代其位置:
如果用x替代5的位置,根据二叉搜索树的性质,有x>2,x<7,保证了删除后的二叉树还是二叉搜索树。

而这个x是被删除结点右子树的最左的孩子 :从被删除结点的右孩子开始,一直找左孩子,直到空为止。

Node* rightMinparent = cur;//记录右子树的最小结点的父节点,用来确保其替换删除结点后,还能继续链接最小结点的右子树
Node* rightMin = cur->_right;
while (rightMin->_left != nullptr)//寻找最小结点
{
    rightMinparent = rightMin;//记录最小结点的父节点
    rightMin = rightMin->_left;
}
cur->_key = rightMin->_key;//交换被删除结点和最小结点的值
if (rightMinparent->_left == rightMin)//链接最小结点的右子树
    rightMinparent->_left = rightMin->_right;
else
    rightMinparent->_right = rightMin->_right;
delete rightMin;//释放被删除节点的空间(因为交换了值,所以此时该结点是被删除结点)
return true;

删除操作的递归写法

递归的整体思路与上述一致,只是对情况3的操作略有不同

  • 若结点为空,则返回
  • 若结点不是要删除结点,则递归其左右
  • 若结点是要删除结点,则执行删除操作

其中,对于情况3的删除操作做了如下处理:

在这里插入图片描述

如上图所示,在删除结点2时,并没有直接对其进行delete操作,而是将其与最小值结点进行了值交换,然后再递归过去删除最小值结点。

if (root == nullptr)
    return false;
if (root->_key > key)
{
    _EraseR(root->_left, key);//递归左子树
}
else if (root->_key < key)
{
    _EraseR(root->_right, key);//递归右子树
}
else
{
    Node* cur = root;
    if (root->_right == nullptr)//情况1、2
    {
        root = root->_left;
    }
    else if (root->_left == nullptr)
    {
        root = root->_right;
    }
    else//情况3
    {
        Node* rightMin = root->_right;
        while (rightMin->_left)
        {
            rightMin = rightMin->_left;
        }
        swap(root->_key, rightMin->_key);//交换值
        return _EraseR(root->_right, key);//继续递归
    }
    delete cur;//释放情况1、2的被删除结点的空间
    return true;
}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值