std :: map
实现的清单,追踪开发人员并询问他们制定决策所使用的标准,因此仍然只能做出猜测。 - Steve Jessop取决于使用情况。AVL树通常有更多的旋转操作进行平衡。所以如果您的应用程序没有太多的插入和删除操作,但是对搜索权重很大,那么AVL树可能是一个不错的选择。
std::map
使用红黑树,因为它在节点插入/删除和搜索速度之间得到了合理的折衷。
AVL树的最大高度为1.44logn,而红黑树的最大高度为2logn。在AVL中插入一个元素可能会在树的某个点上进行重新平衡。重新平衡完成插入。插入新叶子后,必须更新该叶子祖先的内容直至根部,或者到达两个子树深度相等的点。需要更新k个节点的概率是1/3^k。重新平衡时间复杂度为O(1)。删除一个元素可能需要多次重新平衡(最多可以达到树深的一半)。
红黑树是表示为二叉搜索树的4阶B树。B树中的4节点导致等效BST中的两个级别。在最坏情况下,树的所有节点都是2节点,仅有一个3节点链到一个叶子。该叶子将与根距离为2logn。
从根到插入点,必须将4节点更改为2节点,以确保任何插入都不会使叶子结点饱和。从插入点返回时,必须分析所有这些节点,以确保它们正确表示4节点。也可以向下遍历树来完成此操作。全局成本将是相同的。没有免费午餐!从树中删除元素的操作也是同样的顺序。
所有这些树都要求节点携带高度、权重、颜色等信息。只有Splay树不需要额外的信息。但大多数人害怕Splay树,因为它们的结构是随机的!
最后,树还可以在节点中携带权重信息,从而实现权重平衡。可以应用各种方案。当子树包含另一个子树元素的3倍以上时,应进行重新平衡。重新平衡再次通过单个或双旋转完成。这意味着最坏情况下的时间复杂度为2.4logn。可以使用2倍而不是3倍,这是一个更好的比率,但可能意味着在此处和那里留下少于1%的未平衡子树。很棘手!
哪种树是最好的?毫无疑问是AVL树。它们是编码最简单的树,并且它们的最坏高度最接近于logn。对于1000000个元素的树,AVL树的高度至多为29,红黑树为40,而权衡树则因比率而异,可以是36或50。
还有许多其他变量:随机性、添加、删除、搜索等的比例。
这只是你实现的选择 - 它们可以作为任何平衡树来实现。各种选择都是可比较的,只有一些细微的差异。因此,任何一种都是同样好的。
更新于2017-06-14:webbertiger在我评论后编辑了它的回答。我应该指出,现在它的答案在我看来好多了。但是我仍保留我的答案作为额外信息...
由于我认为第一个答案有误(更正:不再有两个了),而第三个答案有错误的断言,我觉得我必须澄清一些事情...
最常见的两种树是AVL和Red Black(RB)。主要区别在于使用方法:
主要区别在于着色。在RB树中,您比AVL树少进行重平衡操作,因为着色使您有时可以跳过或缩短相对较高成本的重平衡操作。由于着色,RB树的节点级别也更高,因为它可以在黑色节点之间接受红色节点(具有~2倍的级别可能性),使搜索(读取)效率稍低...但由于它是常数(2倍),因此保持在O(log n)。
如果考虑修改树的性能损失(显著)与查询树的性能损失(几乎不重要)之间的差异,对于一般情况而言自然会更喜欢RB而不是AVL。
O(logn)
的时间,而值始终会按顺序排序。从C++11开始(我想),有unordered_map
和unordered_set
,它们使用哈希函数实现,虽然它们没有排序,但大多数查询和操作可以在平均情况下以O(1)
完成。 - SomethingSomethingstd::map
中插入或删除元素时,指向其他元素的迭代器不会失效。这使得在一个动态分配的节点中存储多个元素变得非常困难,甚至是不可能的,同时还要满足通常的时间复杂度保证。(对std::map
的查询和更新必须最坏情况下花费对数时间。)因此,在实践中,std::map
的实现必须是某种自平衡二叉树。 - isekaijin