std::map 的排序是如何实现的
How is the ordering of std::map achieved?
我们可以从几个来源看到std::map是使用红黑树实现的。我的理解是,这些类型的数据结构不以任何特定的顺序保存它们的元素,而只是保持BST属性和高度平衡要求。
那么,为什么 map::begin 是常量时间,并且我们能够迭代一个有序序列呢?
从std::map
内部维护 BST 的前提开始(这不是标准的严格要求,但大多数库可能会这样做,就像一棵红黑树(。
在BST中,要找到最小的元素,您只需沿着左边的分支直到到达一个叶子,即O(log(N((。但是,如果你想在恒定的时间内交付"begin(("迭代器,那么在内部跟踪最小的元素是非常简单的。每次插入导致最小的元素发生变化时,您都会更新它,仅此而已。当然,这是内存开销,但这是一种权衡。
可能还有其他方法可以挑出最小的元素(例如故意保持根节点不平衡(。无论哪种方式,都不难做到。
要遍历"有序"序列,您只需按顺序遍历树。从最左边的叶节点开始,你去(上(,(右(,(上,上(,(右(,...等等..这是一组简单的规则,并且易于实现,只需查看我不久前编写的简单BST顺序迭代器的快速实现即可。在执行按顺序遍历时,您将按正确的顺序从最小到最大访问每个节点。换句话说,它只是给你一种错觉,即"数组"被排序了,但实际上,正是遍历使它看起来像是被排序的。
红黑树的平衡属性允许您以 O(log N( 成本在树中的任何位置插入节点。 对于典型的std::map
实现,容器将保持树的排序,并且每当插入新节点时,请将其插入正确的位置以保持树的排序,然后重新平衡树以维护红黑属性。
所以不,红黑树本质上不是排序的。
RB 树是二叉搜索树。二叉搜索树不一定以任何特定顺序存储其元素,但您始终可以获得无序遍历。我不确定 map::begin 如何保证恒定时间,我认为这涉及始终记住最小元素的路径(通常是 O(log(n(((。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 如何实现内部实现依赖于模板参数的类
- 我的 PRNG 实现与我尝试复制的实现有何不同?