数据结构与算法python第十三天

本文详细介绍了二叉查找树(BST)的删除操作,包括没有子节点、一个子节点和两个子节点的情况。在删除节点时,会涉及到节点替换和保持BST性质的策略。对于有两个子节点的节点删除,通过找到后继节点进行替换来维持树的平衡。同时,文章探讨了算法的时间复杂度,并指出在随机分布的数据中,BST的高度接近log2^n,确保了较好的性能。
摘要由CSDN通过智能技术生成

二叉查找树的实现

BST.delete方法

有增就有减,最复杂的delete方法:

  • 用_get找到要删除的节点,然后调用remove来删除,找不到则提示错误
def delete(self, key):
    if self.size > 1:                            #判断是否只剩一个节点
        nodeToRemove = self._get(key, self.root)
        if nodeToRemove:
            self.remove(nodeToRemove)
            self.size = self.size - 1
        else:
            raise KeyError('Error, key not in tree')
    elif self.size == 1 and self.root.key == key:
        self.root = None
        self.size = self.size - 1
    else:
        raise KeyError('Error, key not in tree')

__delitem__特殊方法

def __delitem__(self, key):
    self.delete(key)

在delete中,最复杂的是找到key对应的节点之后的remove节点方法!

BST.remove方法

从BST中remove一个节点,还要求仍然保持BST的性质,分以下三种情形:

  • 这个节点没有子节点
  • 这个节点有一个子节点
  • 这个节点有两个子节点

没有子节点,直接删除

if currentNode.isLeaf():       #leaf
    if currentNode == currentNode.parent.leftChild:
        currentNode.parent.leftChild = None
    else:
        currentNode.parent.rightChild = None
        

一个子节点

  • 解决:将这个唯一的子节点上移,替换掉被删节点的位置
  • 问题:替换操作分几种情况
    • 被删节点的子节点是左?还是右?
    • 被删节点本身是其父节点的左?还是右?
    • 被删节点本身就是根节点?
if currentNode.hasLeftChild():
    if currentNode.isLeftChild():                #左左
        currentNode.leftChild.parent = currentNode.parent
        currentNode.parent.leftChild = currentNode.leftChild   #左子节点删除
    elif currentNode.isRightChild():
        currentNode.leftChild.parent = currentNode.parent
        currentNode.parent.rightChild = currentNode.leftChild   #右子节点删除
    else:
        currentNode.replaceNodeData(currentNode.leftChild.key,  #根节点删除
                           currentNode.leftChild.payload,
                           currentNode.leftChild.leftChild,
                           currentNode.leftChild.rightChild)
else:
    if currentNode.isLeftChild():                            #左子节点删除
        currentNode.rightChild.parent = currentNode.parent
        currentNode.parent.leftChild = currentNode.rightChild
    elif currentNode.isRightChild():                         #右子节点删除
        currentNode.rightChild.parent = currentNode.parent
        currentNode.parent.rightChild = currentNode.rightChild
    else:                                                    #根节点删除
        currentNode.replaceNodeData(currentNode.rightChild.key,
                           currentNode.rightChild.payload,
                           currentNode.rightChild.leftChild,
                           currentNode.rightChild.rightChild)

被删节点有两个子节点

  • 这时无法简单地将某个子节点上移替换被删节点但可以找到另一个合适的节点来替换被删节点,这个合适节点就是被删节点的下一个key值节点,即被删节点右子树中最小的那个,称为“后继”。
elif currentNode.hasBothChildren():      
    succ = currentNode.findSuccessor()   #后继节点
    succ.spliceOut()
    currentNode.key = succ.key
    currentNode.payload = succ.payload

TreeNode类:寻找后继节点

def findSuccessor(self):
    succ = None
    if self.hasRightChild():
        succ = self.rightChild.findMin()
    else:
        if self.parent:             #目前不会遇到
            if self.isLeftChild():
                succ = self.parent
            else:
                self.parent.rightChild = None
                succ = self.parent.findSuccessor()
                self.parent.rightChild= self
    return succ

def findMin(self):
    current = self
    while current.hasLeftChild():
        current = current.isLeftChild
    return current

TreeNode类:摘出节点spliceOut()

def spliceOut(self):                     #摘出叶节点
    if self.isLeaf():
        if self.isLeftChild():
            self.parent.isLeftChild = None
        else:
            self.parent.rightChild = None
    elif self.hasAnyChildren():
        if self.hasLeftChild():
            if self.isLeftChild():
                self.parent.leftChild = self.leftChild
            else:
                self.parent.rightChild = self.leftChild
            self.leftChild.parent = self.parent
        else:
            if self.isLeftChild():                    #摘出带右子节点的节点
                self.parent.leftChild = self.rightChild
            else:
                self.parent.rightChild = self.rightChild
            self.rightChild.parent = self.parent

算法分析(以put为例)

  • 其性能决定因素在于二叉搜索树的高度(最大层次),而其高度又受数据项key插入顺序的影响。
  • 如果key的列表是随机分布的话,那么大于和小于根节点key的键值大致相等
  • BST的高度就是log2**n,(n是节点的个数),而且,这样的树就是平衡树
  • put方法最差性能为O(log2**n)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leopold·Lin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值