我们可以从多个来源看到,std::map是使用红黑树实现的。据我所知,这些类型的数据结构不会按任何特定顺序保存其元素,只是维护BST属性和平衡要求。
那么,为什么map :: begin是常数时间,并且我们能够迭代有序序列呢?
那么,为什么map :: begin是常数时间,并且我们能够迭代有序序列呢?
std::map
在内部维护了一棵二叉搜索树(这不是标准严格要求的,但大多数库可能像红黑树一样做)。在二叉搜索树中,要找到最小元素,只需沿着左侧分支走到达叶子节点,这需要O(log(N))时间。然而,如果您想在常数时间内提供"begin()"迭代器,只需在内部跟踪最小元素即可。每次插入导致最小元素更改时,您都要进行更新。当然,这会增加内存开销,但这是一种权衡。可能还有其他方法可以单独找到最小元素(比如故意保持根节点不平衡)。无论哪种方式,它们都不难实现。std::map
这样的容器并不擅长迭代。树遍历的逻辑,加上你一直在内存中跳来跳去,使得实际性能相当差。因此,将它们用于“主要查找,偶尔有序遍历”或查找值范围等情况。对于快速遍历,通常最好维护一个排序的 std::vector
。我的图表提到了这一点。 - Mikael Persson红黑树是二叉搜索树。二叉搜索树不一定按任何特定顺序存储其元素,但您始终可以获得中序遍历。我不确定 map::begin 如何保证常数时间,我会假设这涉及始终记住到最小元素的路径(通常为 O(log(n)))。
map::begin
是常数时间”的问题 - 实现方案不是在调用begin
时下降到树中(这将是O(log2N)),而是追踪当前树中最小值节点(可能内部选择指针或迭代器 - 最终可能是相同的东西,但是begin
本身显然会返回一个迭代器),在erase
、insert
等操作之后如果有必要进行更新 - 因此可以在常数时间内提供。类似地,最后一个节点也会被类似地追踪(用于rbegin()
)。 - Tony Delroy