【问题标题】:Keeping a binary tree balanced when elements are insert in order按顺序插入元素时保持二叉树平衡
【发布时间】:2011-12-18 05:55:53
【问题描述】:

当已知元素总是按顺序插入时,我想知道是否有合适的算法来保持二叉树的平衡。

对此的一种选择是使用从排序数组或链表创建平衡树的标准方法,如this 问题和this 其他问题中所述。但是,我想要一种方法,可以将一些元素插入树中,然后对其执行查找,然后再添加其他元素,而无需将树分解为列表并重新制作整个事物。

另一种选择是使用许多自平衡树实现中的一种,AVL、AA、Red-Black 等。但是,所有这些都会在插入过程中产生某种开销,而我是考虑到元素总是以递增顺序插入的约束,想知道是否有办法避免这种情况。

所以,为了清楚起见,我想知道是否有一种方法可以保持平衡的二叉树,这样我就可以在任意点插入任意新元素并保持树的平衡,提供新元素在树的排序中大于树中已经存在的所有元素。

例如,假设我有以下树:

       4
      / \
     /   \
    2     6
   / \   / \
  1   3 5   7

如果我知道元素会大于7,有没有一种简单的方法可以在插入新元素时保持平衡?

【问题讨论】:

  • 是作业吗?理论问题?如果是为了实际使用,我会在这些条件下使用skip list 而不是 BST,并且添加始终是最后一个元素。如果这有帮助,虽然它不是一棵树,但请告诉我,我会写下它作为答案。
  • @amit,这也是我的第一个猜测。
  • @amit,这不是一个家庭作业问题,主要是出于好奇/理论。因此,尽管您认为其他数据结构(例如跳过列表(甚至可能指树)可能非常适合)是对的,但我对 BST 执行此操作的方式更感兴趣。

标签: algorithm tree binary-tree


【解决方案1】:

如果您真的有兴趣使用 BST(我认为这不是最佳选择,您可以在我的其他答案中看到),您可以这样做:

BST 正常。这意味着查找是 O(log N),如果我们设法在插入期间保持深度。

当进行插入时(假设我们有一个比之前所有的都大的元素),你从根走到最右边的元素。当你遇到一个子树是完美二叉树的节点时(所有内部节点都有 2 个子节点,所有叶子都在相同的深度),你插入新节点作为这个节点的父节点。

如果你到达树中最右边的节点并且你没有应用前面的规则,这意味着它有一个左孩子,但它没有右孩子。因此,新节点成为当前节点的右孩子。

例如,在下面的第一棵树中,4 的子树不是完美的,但 5 的子树是完美的(根据定义,只有一个节点的树是完美的)。因此,我们将 6 添加为 5 的父节点,这意味着 4 现在是 6 的父节点,而 5 是 6 的左子节点。

如果我们尝试添加另一个节点,那么 4 的子树仍然不是完美的,6 的子树也不是。而 6 是最右边的节点,所以我们添加 7 作为 6 的右孩子。

     4             4             4
    / \           / \           / \
   /   \         /   \         /   \
  2     5 -->   2     6 -->   2     6
 / \           / \   /       / \   / \
1   3         1   3 5       1   3 5   7

如果我们使用这种算法,根的左孩子的子树将永远是完美的,而右孩子的子树的高度永远不会大于左孩子的高度。因此,整棵树的高度总是 O(log N),查找时间也是如此。插入也需要 O(log N) 时间。

与自平衡 BST 相比,时间复杂度相同。但是这个算法应该更容易实现,实际上可能比它们更快。

与我其他答案中基于数组的解决方案相比,查找的时间复杂度相同,但此 BST 的插入时间更差。

【讨论】:

    【解决方案2】:

    对于您描述的要求,您根本不需要树。您只需要一个已排序的dynamic array

    插入时,总是在最后插入(O(1) 摊销)。

    搜索时,使用普通binary search (O(log N))。

    这假设您不需要任何其他操作,或者您不介意它们将是 O(N)。

    【讨论】:

    • 非常感谢您的回答,您说得对,对于按排序顺序接收元素的一般排序集类型的算法,树不是必需的。然而,我更感兴趣(出于好奇)是否有办法用普通的二叉树来做到这一点。再次感谢您的回答。
    【解决方案3】:

    我假设您先验地知道元素是按递增顺序排列的。此外,我想您想要一棵树来快速搜索特定元素。

    我不确定二叉树是否最适合您描述的快速插入。但是可能还有其他数据结构可以很好地处理您描述的用例:尽管我从未使用过它,但skip-list 出现在我的脑海中。由于您总是插入大于集合中所有元素的元素,因此更新指针应该很容易。

    【讨论】:

    • 非常感谢您的回答,您说得对,跳过列表或 svick 建议的动态数组非常适合通常跟踪到达的一组元素但是,由于先验已知的顺序,我更感兴趣的是是否有办法使用二叉树来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 2020-10-07
    • 2021-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多