【问题标题】:Python: BST removal function deleting multiple nodes and reattaching duplicatesPython:BST去除函数删除多个节点并重新附加重复项
【发布时间】:2022-11-16 05:49:02
【问题描述】:

我有 2 个函数可以从二叉搜索树中删除节点。第一个是删除树的根,第二个是删除树中的任何其他节点。

问题是在第 3 次迭代后进行测试时,事情开始变得不稳定。 DEL: 45 行删除节点 45、30、20,而 DEL: 40 行不删除 40 但删除 40 之后的所有内容并重复重新附加 30、20、45。

我感觉 while 循环出了点问题,不管是什么问题,都在进入下一组循环并破坏树。

预期结果应该只删除描述的值,并使树结构尽可能接近原来的样子。我在重新连接现有节点时做错了什么? 我调试的时候发现

        if node.right is None and node.left is None:
            pn.right = None
            pn.left = None

是什么从 DEL 45 行中删除节点 20 和 30

    def remove_start_node(self) -> bool:
        """
        deletes the root note of the BST. first checks if the BST is empty and if there
        is only the root exists. If empty, return False. If only the root exists, delete the root node.
        else, find the in order successor of the root node(leftmost child of the right subtree.)
        if the deleted node only has a left subtree,the left node becomes the rood node of the subtree.
        """

        if self._root is None:
            return False
        if self._root.left is None and self._root.right is None:
            self._root = None
        elif self._root.right is None:  # checks if only left subtree exists
            self._root = self._root.left
        else:
            subtree = self._root.right
            par_tree = subtree
            while subtree.left is not None:  # traverse down till the in order successor is found (leftmost child)
                par_tree = subtree
                subtree = subtree.left
            if subtree != self._root.right:  # reestablish structure
                par_tree.left = subtree.right
                subtree.right = self._root.right
            subtree.left = self._root.left
            self._root = subtree
        return True

    def remove(self, value) -> bool:
        """
        first traverses throughout the BST and deletes the target value while restructuring the BST.
        # first checks if BST is empty, if there is only one node, and if the value is contained within the BST.
        # if empty, return False. if only node, delete the root node. else, find the in order successor of the current
        # node which is the leftmost child of the right subtree of the current node. If the deleted node only has the
        # left subtree, the current node becomes the rood node of the left subtree.
        """

        if not self.contains(value):  # check if the value exists
            return False
        if self._root is None:  # checks if BST is empty
            return False
        if self._root.value == value:  # checks if the value matches the root node
            self.remove_start_node()
            return True

        # traverse through the tree first until the value is found
        x = self._root
        pn = None
        while x is not None:  # traverse through the tree
            if x.value == value:
                node = x
                break
            elif value < x.value:
                pn = x
                x = x.left
            else:
                pn = x
                x = x.right

        # if successor has no children, parent node's children is updated to None
        if node.right is None and node.left is None:
            pn.right = None
            pn.left = None
        elif node.right is None:  # if successor only has a left child, point parent to its children
            pn.right = node.left
        else:  # once successor is found, traverse to the left most child
            subtree = node.right
            par_tree = subtree
            while subtree.left is not None:
                par_tree = subtree
                subtree = subtree.left
            if subtree != node.right:  # reestablish structure
                par_tree.left = subtree.right
                subtree.right = node.right
            pn.right = subtree  # point parent to new subtree
            temp = node.left  # store any other subtrees from the deleted node
            node = subtree  # replace successor with current node
            node.left = temp  # reattach remaining subtrees
        return True
-------------------------------
INPUT  : BST pre-order { 1, 2, 3 } DEL: 1
RESULT : BST pre-order { 2, 3 }
INPUT  : BST pre-order { 1, 2, 3 } DEL: 2
RESULT : BST pre-order { 1, 3 }
INPUT  : BST pre-order { 1, 2, 3 } DEL: 3
RESULT : BST pre-order { 1, 2 }
INPUT  : BST pre-order { 50, 40, 30, 20, 45, 60, 70, 80 } DEL: 0
RESULT : BST pre-order { 50, 40, 30, 20, 45, 60, 70, 80 }
**INPUT  : BST pre-order { 50, 40, 30, 20, 45, 60, 70, 80 } DEL: 45
RESULT : BST pre-order { 50, 40, 60, 70, 80 }
INPUT  : BST pre-order { 50, 40, 30, 20, 45, 60, 70, 80 } DEL: 40
RESULT : BST pre-order { 50, 40, 30, 20, 45, 30, 20, 45, 30, 20 }**
INPUT  : BST pre-order { 50, 40, 30, 20, 45, 60, 70, 80 } DEL: 30
RESULT : BST pre-order { 50, 40, 30, 20, 20, 60, 70, 80 }

【问题讨论】:

  • 根节点并没有什么特别之处。有趣的情况是一棵空树(什么都不做),一个没有孩子的节点(删除节点),一个只有一个孩子的节点(用那个孩子替换节点)和一个有两个孩子的节点。最后一种情况比较棘手,因为它涉及选择两个孩子中的一个来替换节点,并将另一个孩子移植到以所选节点为根的子树中。

标签: python data-structures binary-search-tree


【解决方案1】:

其中一些问题是:

  • 在“简单”的情况下,您假设最后一次下降是通过选择正确的孩子来实现的,因为您将 pn.right 设置为某物,但很可能您是通过左孩子来的,然后您应该设置 pn.left .

  • par_tree 未初始化为正确的节点。为了保持一致,它应该设置为subtree的父级,即node

  • 我不清楚“重建结构”的部分。 cmets 没有反映正在发生的事情。例如,node = subtree 不会“用当前节点替换后继节点”……它只是设置一个名称。但更重要的是。常见的算法是获取 subtree 的值并将其存储在 node 中,然后从树中删除 subtree (这是一个“简单”的情况,因为它没有左孩子)。

没问题,但是:

  • 没有必要写一个完整的删除根的方法。这些操作非常相似,您可以用一种方法处理它们。

  • 不必先调用contains 来查看该值是否存在。这是在执行移除算法时自然会出现的东西。

这是一个建议的修复——cmets 指示主要更改

    def remove(self, value) -> bool:
        if self._root is None:
            return False
        x = self._root
        pn = None
        while x is not None:
            if x.value == value:
                node = x
                break
            elif value < x.value:
                pn = x
                x = x.left
            else:
                pn = x
                x = x.right
        else:
            return False  # not found
        # Deal with easy cases in one block of code
        if node.right is None or node.left is None:
            if not pn:  # Case where the root is deleted
                self._root = node.left or node.right
            # Be aware: node could be either the left or right child of its parent
            elif pn.left is node:
                pn.left = node.left or node.right
            else:
                pn.right = node.left or node.right
        else:
            par_tree = node
            subtree = node.right
            while subtree.left is not None:
                par_tree = subtree
                subtree = subtree.left
            # Don't delete node, but its value, and delete subtree-node instead 
            # Move the value of subtree
            node.value = subtree.value
            # Then remove that node (easy case)
            if par_tree.left == subtree:
                par_tree.left = subtree.right
            else:
                par_tree.right = subtree.right
        return True

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-30
    • 1970-01-01
    • 2017-02-03
    • 2019-01-02
    • 2016-11-09
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多