可以提示插入到标准::地图导致不平衡的树

Can hinted insert to std::map lead to unbalanced tree?

本文关键字:不平衡 地图 提示 插入 标准      更新时间:2023-10-16

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

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

或者换句话说:"暗示插入"会根据需要重新平衡底层树吗?

Afaik,C++标准并不能保证这一点,但我想知道在这种情况下大多数流行的实现的行为方式。

无论有序关联容器的底层实现如何(标准没有指定,尽管它通常是一个自平衡二叉搜索树),提示插入(iterator insert( const_iterator hint, const value_type& value );)的要求都可以通过以下简单的算法来满足:

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

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

  3. 否则,请忽略该提示。

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

如果提示不正确,则忽略提示是完全可以接受的,因此提供不正确的提示不会导致数据结构有任何差异;它仍然像插入之前一样平衡(对数可访问)。但是提供不正确的提示会强制计算 O(1) 额外的比较,因此只有在提示通常正确的情况下,对于"通常"的某个值,才应使用提示版本的插入。

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

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

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

std::mapstd::set被实现为红黑树。

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

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

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