当前位置: 首页 > 知识库问答 >
问题:

删除最小二叉查找树Python

锺离浩慨
2023-03-14

我试图从BST中删除最小节点,所以我在树中搜索,直到得到最小值(当root.leftnode为None时),然后将root.rightnode设置为根本身,以继续BST。

问题是,当我这样做之后检查树时,它不会显示曾经发生过的删除。

有人可以指出我正确的方向吗,任何建议都值得赞赏。

class node():

    def __init__(self, key, data):

        self.data = data
        self.key = key
        self.leftnode = None
        self.rightnode = None
        self.count = 1


class binarysearch():

    def __init__(self):

        self.size = 0
        self.rootnode = None

    def insert(self, key, data):

        if self.rootnode is None:
            self.rootnode = node(key, data)
        else:
            self.insertnode(self.rootnode, key, data)

    def getroot(self):

        return self.rootnode

    def insertnode(self, root, key, data):

            if root.key == key:
                root.data = data

            elif key < root.key:
                if root.leftnode is None:                    
                    root.leftnode = node(key, data)
                else:
                    self.insertnode(root.leftnode, key, data)
            else:
                if root.rightnode is None:
                    root.rightnode = node(key, data)
                else:
                    self.insertnode(root.rightnode, key, data)

            root.count = 1 + self.sizenode(root.leftnode) + self.sizenode(root.rightnode)

    def inorder(self, root):

        if root is not None:

            self.inorder(root.leftnode)
            print(root.key)
            self.inorder(root.rightnode)

    def deletemin(self):

        if self.rootnode is None:
            print("No nodes exist")
        else:
            self.deleteminnode(self.rootnode.leftnode)

    def deleteminnode(self, root):

        if root.leftnode is not None:
            self.deleteminnode(root.leftnode)
        else:
            print (root.key, "deleted")
            root = root.rightnode


if __name__ == '__main__':

    a = binarysearch()
    a.insert(7,7)
    a.insert(1,1)
    a.insert(8,8)
    a.insert(3,3)
    a.insert(9,9)
    a.insert(2,2)
    a.insert(4,4)
    a.insert(11,11)
    a.insert(10,10)
    a.deletemin()
    a.getnodes()

共有2个答案

贝德辉
2023-03-14

您可以查找树中的所有节点以及该节点的路径,查找结果的最小值,然后遍历生成的路径以删除该节点:

class Tree:
  def __init__(self, **kwargs):
    self.__dict__ = {i:kwargs.get(i) for i in ['val', 'left', 'right']}
  def get_nodes(self, current = []):
    yield [''.join(current), self.val] 
    yield from getattr(self.right, 'get_nodes', lambda _:[])(current+['1'])
    yield from getattr(self.left, 'get_nodes', lambda _:[])(current+['0'])
  def __iter__(self):
    yield self.val
    yield from [[], self.left][bool(self.left)]
    yield from [[], self.right][bool(self.right)]
  def _insert_back(self, _v):
    if not self.val:
      self.val = _v
    else:
      if _v < self.val:
         getattr(self.left, '_insert_back', lambda x:setattr(x, 'left', Tree(val=x)))(_v)
      else:
         getattr(self.right, '_insert_back', lambda x:setattr(x, 'right', Tree(val=x)))(_v)
  def remove(self, _path, _to_val, last=None):
     '''_to_val: if _to_val is None, then the item is removed. If not, the node value is set to _to_val'''
     if _path:
       getattr(self, ['left', 'right'][int(_path[0])]).remove(_path[1:], _to_val, last = self)
     else:
       if _to_val is None:
         last.left = None
         last.right = None
         for i in [[], self.left][bool(self.left)]:
           last._insert_back(i)
         for i in [[], self.right][bool(self.right)]:
            last._insert_back(i)
       else:
         self.val = _to_val

创建:

     7 
  5     9
4   6  8  10
            12
t = Tree(val = 7, left=Tree(val = 5, left=Tree(val=4), right=Tree(val=6)), right=Tree(val=9, left=Tree(val=8), right=Tree(val=10, right=Tree(val=12))))
path, _to_remove = min(t.get_nodes(), key=lambda x:x[-1])
print(f'Removing {_to_remove}')
t.remove(path, None)
print([i for i in t])

输出:

4
[7, 5, 9, 8, 10, 12]
慕容坚
2023-03-14

您遇到的问题是< code>root = root.rightnode仅重新绑定局部变量< code>root。它不会改变您引用该节点的其他位置(如树中的父节点)。

要解决此问题,您需要更改递归函数的工作方式。它不应该期望它在最后一次调用中完成所有工作,而应该返回应该是其父节点的左节点的值。然后,这将是节点本身,但对于最小节点,它将是其正确的子节点。

def deletemin(self):
    if self.rootnode is None:
        print("No nodes exist")
    else:
        self.rootnode = self.deleteminnode(self.rootnode)

def deleteminnode(self, root):
    if root.leftnode is not None:
        root.leftnode = self.deleteminnode(root.leftnode)
        return root
    else:
        return root.rightnode

关于名称的最后一个注意事项:使用root作为树中随机节点的名称有点奇怪。通常一棵树只有一个根节点,其他节点不被称为root,因为它们有父节点。不幸的是,您的节点类已经使用了最传统的名称node。通常,类应该被赋予大写名称,这样lowercase_names可以独占地引用实例和其他变量。不过这只是惯例(像<code>list</code>这样的内置类型打破了规则)。如果您使用标准名称样式,其他人可能更容易理解您的html" target="_blank">代码,但Python不会强制执行这些样式。它将允许您使用任何您想要的名称。即使名称<code>self</code>也不是必需的,尽管如果您在没有充分理由的情况下对方法的第一个参数使用了不同的名称,这将非常令人困惑(一个很好的例子:类方法和元类的方法通常使用<code<cls</code>作为它们的第一个变量的名称,因为对象将是一个类)。

 类似资料:
  • 我现在正在读一本关于从二叉搜索树中删除节点的书,书中描述的过程对我来说似乎不必要地复杂。 在1号情况下,如果我们删除40,它将替换为30;在 2 号情况下,如果我们删除 40,它将被替换 35。 但在书中,它说应该从要删除的节点的右子树中找到替换,这可能涉及一些复杂的操作。 我在这里遗漏了什么吗?请指出。

  • 我试图递归地在二叉树中找到最小值(不是二叉查找树)。让我困惑的是基本情况。如果TreeNode t为空,返回什么?因为我将使用返回的值将其与当前的最小值进行比较(我认为),我相信我返回的内容很重要。

  • 主要内容:什么是二叉排序树?,使用二叉排序树查找关键字,二叉排序树中插入关键字,二叉排序树中删除关键字,总结前几节介绍的都是有关静态 查找表的相关知识,从本节开始介绍另外一种查找表—— 动态查找表。 动态查找表中做查找操作时,若查找成功可以对其进行删除;如果查找失败,即表中无该关键字,可以将该关键字插入到表中。 动态查找表的表示方式有多种,本节介绍一种使用树结构表示动态查找表的实现方法—— 二叉排序树(又称为 “二叉查找树”)。 什么是二叉排序树? 二叉排序树要么是空 二叉树,要么具有如下特点:

  • 我正在努力实现二叉搜索树。完成实现所需的功能之一是重新平衡功能。 根据规范,该功能的工作方式如下: rebalance() 方法应创建一个平衡树,从而将偏度降低为零。平衡树是指在整个树中,左子树和右子树的大小相差不超过1(即,每个子树也是平衡的)。 为了平衡树,rebalance() 方法应反复将根值移动到较小的子树,并将最小/最大值从较大的子树移动到根,直到树平衡。然后,它应该以递归方式平衡两个

  • 我正在做一个AlgoExpert挑战,我已经花时间自己解决它,看了关于它的视频讲座,我觉得我有一个很好的理解,但我在递归和树遍历方面的技能现在很低(这就是我工作的原因)。 这是提示 编写一个函数,该函数接受二进制搜索树(BST)和目标整数值,并返回与BST中包含的目标值最接近的值。每个BST节点都有一个整数值、一个左子节点和一个右子节点。其子节点本身是有效的BST节点或无/空 目标:12 这是我目

  • 在二元搜索树的情况下,为什么我们不能简单地在一个节点有两个子节点的情况下,将一个节点的前一个节点替换为后一个节点?