【问题标题】:Can hinted insert to std::map lead to unbalanced tree?暗示插入 std::map 会导致树不平衡吗?
【发布时间】:2018-05-18 02:06:11
【问题描述】:

这是否会导致 std::map/set 中的不平衡树(以及随后的较差搜索性能):

std::set<int> s;
for(int i = 0; i< 1000; ++i)
    s.insert(s.end(), i);

?

或者换句话说:“提示插入”是否会根据需要重新平衡底层树?

Afaik,C++ 标准不保证这一点,但我想知道最流行的实现在这种情况下如何表现。

【问题讨论】:

  • 我认为它不会,毕竟实现可能已经优化为插入有序序列。实际上,在这种特殊情况下,提示是不必要的(有一些不必要的开销)。
  • @alfC 这被证明是一个有趣的问题......如果树在每次提示(正确与否)插入时重新平衡自身 - 这棵树是否提供“摊销常数”保证? (毕竟重新平衡不是免费的)如果它不重新平衡 - 某些插入序列不会导致不平衡树吗?

标签: c++


【解决方案1】:

不管有序关联容器的底层实现如何(标准没有规定,虽然通常是自平衡二叉搜索树),对hinted insert(iterator insert( const_iterator hint, const value_type&amp; value );)的要求可以满足如下简单算法:

  1. 将值与 *hint 和 *prev(hint) 进行比较

  2. 如果它适合它们,请将其插入那里。

  3. 否则,忽略提示。

只要prev(hint) 是摊销常数时间,只要hint 是正确的,该算法就是摊销常数时间。 (“正确”是指插入点之后的位置。)

如果提示不正确,完全可以忽略它,因此提供不正确的提示不会对数据结构造成任何影响;它仍然与插入之前一样平衡(可对数访问)。但是提供不正确的提示会强制计算 O(1) 额外的比较,因此只有在提示通常正确的情况下才应该使用插入的提示版本,对于“通常”的某些值。

一个常见的用例是已经对要插入的条目进行了搜索,因此插入位置肯定是已知的。这避免了在插入之前需要执行某些操作时进行两次搜索的开销,而不会在其他进程修改 find() 和提示 insert() 之间的 set 的情况下牺牲安全性(当然,假设有适当的锁定) )。

【讨论】:

  • @Caleth:是的。谢谢。
  • 你确定 O(1) 吗?我预计它是 O(log n),就像在非提示插入的情况下一样。此外,这并不能真正回答原始问题
  • @c.m.:如果提示正确(即它是插入点之后的位置),它是摊销的常数时间。我虽然很清楚,但我添加了更多的词来强调这一点。您最初的问题是“是否提供提示会导致树不平衡”,我声明“它仍然与插入之前一样平衡(可对数访问)。”这对我来说似乎是一个答案:) 如果不够明确,请告诉我原因。
  • 您的意思是“除了执行正常插入所需的 O(log n) 之外,提供不正确的提示会导致 O(1) 比较”?
  • 实际上,我有一个方便的:cs.princeton.edu/~fiebrink/423/… 请参阅第 12 页的红黑树部分。
【解决方案2】:

没有。树将保持平衡,因为这是std::set 的不变量的一部分。否则,它无法保证对数查找时间(最坏的情况是线性的)。

“提示”只是一个提示 - 不是“在此处插入”的要求

【讨论】:

  • 你确定它是“std::setinvariant”的一部分吗?我在我的标准副本中找不到任何这样的承诺......或者你指的是红黑树,它(显然)是最流行的现代实现?
  • @C.M. - a.insert(p, t) 的要求 (Table 84) 是:“t 插入到尽可能靠近 p 之前的位置。” p 并没有说确切
  • @BoPersson 这与我的问题有什么关系?特别是,考虑到您的链接是这样说的:“......但是如果 t 在 p 之前插入,则摊销常数。”
【解决方案3】:

std::mapstd::set 实现为 Red-Black Trees

这意味着任何子树的最长分支不超过该子树最小分支的两倍(也适用于根)。

因此,您可以期望您的 查找 操作所花费的时间不会超过完美平衡树的两倍

您的 insertremove 操作可能需要更长的时间(因为树可能会重新平衡),但仍是 O(log n)(未摊销)。

【讨论】:

  • 那么,std::map 实现为红黑树获得“平衡”保证作为该类型结构的固有属性?这意味着暗示插入可能比我想象的更昂贵......
  • @C.M.它几乎和你能经历的一样好。如果数据有用(自动平衡树),平衡步骤就非常简单。
  • 它们没有保证被实现为红黑树。
  • @xskxzr 你是对的。但是 C.M.正在询问最流行的实现,所以我认为它符合条件。
  • @GillBates 你知道红黑树中(正确)提示插入操作的复杂性吗?在这样的std::map 中使用提示插入有什么意义吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-24
  • 1970-01-01
  • 2011-11-29
  • 1970-01-01
  • 2017-05-09
  • 1970-01-01
相关资源
最近更新 更多