返回

操作树的结点- 从树中移除某个键

前端

计算机体系中,树是一种非常重要的数据类型,我们前面学了如何插入一个结点,这篇文章我们来实现树的remove方法。

树的remove方法,又叫作删除(deletion)或者说摧毁(destruction)。 它有两种变种:

  • remove(key):删除一个特定的结点
  • remove_subtree(key):删除一个子树

我们先来看第一个。 从树中删除一个特定的结点:

  • 如果一个结点的键和要删除的结点的键相等,那么就删除它。
  • 否则,比较结点和要删除的结点的键,依此递归删除树的左或右子树。

这里有一个需要注意的细节:在删除一个结点的时候,我们还需要更新结点的父结点的信息。在上面的这个算法中,我们没有做这个事情。这一般是根据树的实现来做的。 如果我们是把树作为一个数组来存储,那么父结点的索引就是结点索引整除以二。 如果结点的索引是偶数,那么它就是左结点,否则它是右结点。

func delete_node(tree, key):
  # 寻找要删除结点
  node = tree.find(key)
  if node is None:
    return

  # 删除结点及其后代
  def delete_subtree(node):
    if node.left is None and node.right is None:
      return
    if node.left is None:
      delete_subtree(node.right)
    elif node.right is None:
      delete_subtree(node.left)
    else:
      delete_subtree(node.left)
      delete_subtree(node.right)
    node.left = None
    node.right = None

  # 更新结点及其祖先结点的count
  def update_node_count(node):
    if node.left is None and node.right is None:
      return 1
    if node.left is None:
      return 1 + update_node_count(node.right)
    elif node.right is None:
      return 1 + update_node_count(node.left)
    else:
      return 1 + update_node_count(node.left) + update_node_count(node.right)

  delete_subtree(node)
  update_node_count(node)

第一个是容易的,很容易实现。第二个是 difficult,因为有很多细节要考虑。我们这里简单的说一下。

  • 如果一个结点有两个后代,那么我们只需要删除这个结点的后代。
  • 如果一个结点只有一个后代,那么我们只需要删除这个结点的后代,然后把这个结点的后代的父结点设为这个结点的父结点。
  • 如果一个结点没有后代,那么我们只需要从这个结点的父结点的children数组中删掉这个结点。