在 python 中删除二叉搜索树中的节点?

Deleting nodes in a binary search tree in python?

所以我在计算机科学中遇到了一个问题 class,它要求我扩展我们之前编写的二叉搜索树 class,并添加一种从中删除节点的方法树,如果该节点有 0、1 或 2 个子节点,则必须考虑这一点。查看条件和内容后,我得出结论,我需要找到指定节点的父节点才能执行此操作,因为已删除节点的子节点将分配给父节点。 这就是我卡住的地方,因为我们最近才开始研究节点和链表,我对此还是很陌生,这就是为什么我不知道如何跟踪父节点。

这是 BST 的代码 class:

导入副本

class _BSTNode:

    def __init__(self, value):
        """
        -------------------------------------------------------
        Creates a node containing a copy of value.
        Use: node = _BSTNode( value )
        -------------------------------------------------------
        Preconditions:
          value - data for the node (?)
        Postconditions:
          Initializes a BST node containing value. Child pointers are None, height is 1.
        -------------------------------------------------------
        """
        self._value = copy.deepcopy(value)
        self._left = None
        self._right = None
        self._height = 1
        return

    def _update_height(self):
        """
        -------------------------------------------------------
        Updates the height of the current node.
        Use: node._update_height()
        -------------------------------------------------------
        Postconditions:
          _height is 1 plus the maximum of the node's (up to) two children.
        -------------------------------------------------------
        """
        if self._left is None:
            left_height = 0
        else:
            left_height = self._left._height

        if self._right is None:
            right_height = 0
        else:
            right_height = self._right._height

        self._height = max(left_height, right_height) + 1
        return

    def __str__(self):
        """
        -------------------------------------------------------
        DEBUG: Prints node height and value.
        -------------------------------------------------------
        """
        return "h: {}, v: {}".format(self._height, self._value)

class BST:

    def __init__(self):
        """
        -------------------------------------------------------
        Initializes an empty BST.
        Use: bst = BST()
        -------------------------------------------------------
        Postconditions:
          Initializes an empty bst.
        -------------------------------------------------------
        """
        self._root = None
        self._count = 0
        return

    def is_empty(self):
        """
        -------------------------------------------------------
        Determines if bst is empty.
        Use: b = bst.is_empty()
        -------------------------------------------------------
        Postconditions:
          returns:
          True if bst is empty, False otherwise.
        -------------------------------------------------------
        """
        return self._root is None

    def __len__(self):
        """
        -------------------------------------------------------
        Returns the number of nodes in the BST.
        Use: n = len( bst )
        -------------------------------------------------------
        Postconditions:
          returns:
          the number of nodes in the BST.
        -------------------------------------------------------
        """
        return self._count

    def insert(self, value):
        """
        -------------------------------------------------------
        Inserts a copy of value into the bst.
        Use: b = bst.insert( value )
        -------------------------------------------------------
        Preconditions:
          value - data to be inserted into the bst (?)
        Postconditions:
          returns:
          inserted - True if value is inserted into the BST,
          False otherwise. Values may appear only once in a tree. (bool)
        -------------------------------------------------------
        """
        self._root, inserted = self._insert_aux(self._root, value)
        return inserted

    def _insert_aux(self, node, value):
        """
        -------------------------------------------------------
        Inserts a copy of _value into node.
        Private recursive operation called only by insert.
        Use: node, inserted = self._insert_aux( node, value )
        -------------------------------------------------------
        Preconditions:
          node - a bst node (_BSTNode)
          value - data to be inserted into the node (?)
        Postconditions:
          returns:
          node - the current node (_BSTNode)
          inserted - True if value is inserted into the BST,
          False otherwise. Values may appear only once in a tree. (boolean)
        -------------------------------------------------------
        """
        if node is None:
            # Base case: add a new node containing the value.
            node = _BSTNode(value)
            self._count += 1
            inserted = True
        elif value < node._value:
            # General case: check the left subtree.
            node._left, inserted = self._insert_aux(node._left, value)
        elif value > node._value:
            # General case: check the right subtree.
            node._right, inserted = self._insert_aux(node._right, value)
        else:
            # Base case: value is already in the BST.
            inserted = False

        if inserted:
            # Update the current node height if any of its children have been changed.
            node._update_height()
        return node, inserted

    def retrieve(self, key):
        """
        -------------------------------------------------------
        Retrieves a copy of a value matching key in a BST. (Iterative)
        Use: v = bst.retrieve( key )
        -------------------------------------------------------
        Preconditions:
          key - data to search for (?)
        Postconditions:
          returns:
          value - value in the node containing key, otherwise None (?)
        -------------------------------------------------------
        """
        node = self._root
        value = None

        while node is not None and value is None:

            if key < node._value:
                node = node._left
            elif key > node._value:
                node = node._right
            else:
                value = copy.deepcopy(node._value)
        return  value

    def inorder(self):
        """
        -------------------------------------------------------
        Prints the contents of the tree in inorder order.
        -------------------------------------------------------
        Postconditions:
          The contents of the tree are printed inorder.
        -------------------------------------------------------
        """
        if self._root is not None:
            self._inorder_aux(self._root)
        return

    def _inorder_aux(self, node):
        """
        -------------------------------------------------------
        Prints the contents of the subtree at node.
        -------------------------------------------------------
        Preconditions:
          node - a bst node (_BSTNode)
        Postconditions:
          prints:
          the values at the subtree of node in inorder
        -------------------------------------------------------
        """
        if node._left is not None:
            self._inorder_aux(node._left)
        print(node._value)
        if node._right is not None:
            self._inorder_aux(node._right)

        return

    def postorder(self):
        """
        -------------------------------------------------------
        Prints the contents of the tree in postorder order.
        -------------------------------------------------------
        Postconditions:
          The contents of the tree are printed postorder.
        -------------------------------------------------------
        """
        if self._root is not None:
            self._postorder_aux(self._root)
        return

    def _postorder_aux(self, node):
        """
        -------------------------------------------------------
        Prints the contents of the subtree at node.
        -------------------------------------------------------
        Preconditions:
          node - a bst node (_BSTNode)
        Postconditions:
          prints:
          the values at the subtree of node in postorder
        -------------------------------------------------------
        """
        if node._left is not None:
            self._preorder_aux(node._left)
        if node._right is not None:
            self._preorder_aux(node._right)
        print(node._value)


        return

    def preorder(self):
        """
        -------------------------------------------------------
        Prints the contents of the tree in preorder order.
        -------------------------------------------------------
        Postconditions:
          The contents of the tree are printed preorder.
        -------------------------------------------------------
        """
        if self._root is not None:
            self._preorder_aux(self._root)
        return

    def _preorder_aux(self, node):
        """
        -------------------------------------------------------
        Prints the contents of the subtree at node.
        -------------------------------------------------------
        Preconditions:
          node - a bst node (_BSTNode)
        Postconditions:
          prints:
          the values at the subtree of node in preorder
        -------------------------------------------------------
        """

        print(node._value)
        if node._left is not None:
            self._postorder_aux(node._left)
        if node._right is not None:
            self._postorder_aux(node._right)
        return


    def traverse(self):
        """
        ---------------------------------------------------------
        Returns the contents of bst in an array in sorted order.
        ---------------------------------------------------------
        Postconditions:
          returns:
          a - an array containing the contents of bst in sorted order.
        ---------------------------------------------------------
        """
        a = []
        self._traverse_aux(self._root, a)
        return a

    def _traverse_aux(self, node, a):
        """
        ---------------------------------------------------------
        Traverse the node's subtree in inorder, adding the contents of
        each node to an array
        ---------------------------------------------------------
        Preconditions:
          node - the root of a subtree (_BSTNode)
        Postconditions:
          a - contains the contents of the subtree of node 
                    in sorted order.
        ---------------------------------------------------------
        """
        if node._left is not None:
            self._traverse_aux(node._left, a)
        a.append(node._value)
        if node._right is not None:
            self._traverse_aux(node._right, a)


        return

    def is_identical(self, rhs):
        """
        ---------------------------------------------------------
        Determines whether two BSTs are identical.
        Use: b = bst.is_identical( rhs )
        -------------------------------------------------------
        Preconditions:
          rhs - another bst (BST)
        Postconditions:
          returns:
          identical - True if this bst contains the same values
          in the same order as rhs, otherwise returns False.
        -------------------------------------------------------
        """
        identical = self._is_identical_aux(self._root, rhs._root)
        return identical

    def _is_identical_aux(self, node1, node2):
        """
        ---------------------------------------------------------
        Determines whether two subtrees are identical.
        Use: b = bst.is_identical( node1, node2 )
        -------------------------------------------------------
        Preconditions:
          node1 - node of the current BST (_BSTNode)
          node2 - node of the rhs BST (_BSTNode)
        Postconditions:
          returns:
          result - True if this stubtree contains the same values as rhs
          subtree in the same order, otherwise returns False.
        -------------------------------------------------------
        """
        result = True
        if node1._value != node2._value:
            result = False
        if node1._left is not None and node2._left is not None and result == True:
            result = self._is_identical_aux(node1._left, node2._left)
        if node1.right is not None and node2._right is not None and result == True:
            result = self._is_identical_aux(node1._right, node2._right) 



        return result

    def leaf_count(self):
        """
        ---------------------------------------------------------
        Returns the number of leaves (nodes with no children) in bst.
        Use: n = bst.leaf_count()
        (Recursive algorithm)
        ---------------------------------------------------------
        Postconditions:
          returns:
          n - number of nodes with no children in bst.
        ---------------------------------------------------------
        """
        n = self._leaf_count_aux(self._root)
        return n

    def _leaf_count_aux(self, node):
        """
        ---------------------------------------------------------
        Returns the number of leaves (nodes with no children) in bst.
        Use: n = bst.leaf_count()
        (Recursive algorithm)
        ---------------------------------------------------------
        Preconditions:
          node - a BST node (_BSTNode)
        Postconditions:
          returns:
          n - number of nodes with no children below node.
        ---------------------------------------------------------
        """
        count = 0
        if node._left is None and node._right is None:
            count += 1
        if node._left is not None and node._right is None:
            count += self._leaf_count_aux(node._left)
        if node._left is None and node._right is not None:
            count += self._leaf_count_aux(node._right)
        if node._left is not None and node._right is not None:
            count += self._leaf_count_aux(node._left)
            count += self._leaf_count_aux(node._right)


        return count
    def _delete_node(self, node):
        """
        -------------------------------------------------------
        Removes a node from the bst.
        Use: node = self._delete_node(node)
        -------------------------------------------------------
        Preconditions:
          node - the bst node to be deleted (_BSTNode)
        Postconditions:
          returns:
          node - the node that replaces the deleted node. This node is the node
          with the maximum value in the current node's left subtree (_BSTNode)
        -------------------------------------------------------
        """

        # Your code here.

        return node

    def parent_i(self, key):
        """
        ---------------------------------------------------------
        Returns the value of the parent node of a key node in a bst.
        ---------------------------------------------------------
        Preconditions:
          key - a key value (?)
        Postconditions:
          returns:
          value - a copy of the value in a node that is the parent of the
          key node, None if the key is not found.
        ---------------------------------------------------------
        """

        # Your code here

        return value

BST中的最后两个函数class、parent_i和_delete_node是我想写的,注释是我的老师为这些函数写的条件我们需要写。我想如果我找到一种方法来获取父级,那么删除功能应该很容易做到,但现在我不知道从哪里开始。帮助将不胜感激!此外,中间的几个功能,如 min_i 和 max_i 应该是这样的,可能是为了我们 class 中的未来作业或实验室供我们编写。

提前致谢!

编辑:好的,所以我现在理解了结构,但现在我很困惑如果我尝试删除一个有 2 个子节点的节点,而 2 个子节点中较高的一个也有 2 个子节点,等等上?我应该怎么做才能让它适用于所有大小的所有 bsts?

  • 要确定节点的parent,将变量初始设置为None。现在,当您对节点进行二进制搜索时,将该变量设置为您之前所在的任何节点,一旦您找到该节点

  • ,该变量就会给您 parent
  • 当您尝试删除一个节点时,有您提到的3种情况。前 2 个很容易解决,只需用 1 child 替换删除的节点即可。 棘手的情况是当你有 2 children 时。 有两种方法可以解决这个问题,你可以用它的中序后继节点替换那个节点,即紧随其后的节点(最左边的 child 这个节点的右边 child),或者用它的inorder 前驱,即出现在这个节点之前的节点(该节点左侧 child 的最右侧 child)。

  • 这只是对实际发生情况的快速 运行 了解,但现在您应该很明显不需要明确找到 parent一个节点为了删除该节点,只需在您前往需要删除的节点时跟踪前一个节点就足够了。

有关详细信息,请参阅此example