对std::集进行迭代是如何返回排序结果的
How iterating over a std::set returns sorted results
容器std::set(或std::map)是STL提供的数据结构。在几乎所有的编译器中,它都被实现为R&具有保证log(n)插入、查找和删除时间的B树。
https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
在红黑树中,元素是根据存储元素的"less"运算符进行排序的。所以基本上,如果一个根是N+1,N将在左子树上,而N+2将在右子树上,这个顺序将由较少的运算符决定。
我的问题是在执行以下代码时:
set<unsigned long>::iterator it;
for (it = myset.begin(); it != myset.end(); it++) {
cout << *it;
}
元素按排序顺序返回。考虑到底层数据结构是一棵红黑树,这怎么可能呢?是否存储了一个单独的链表,以便能够从最左边的子树迭代到最右边的子树?如果不是,使用R&B树?
我们可以通过查看源代码(本例中为libstdc++5.2.1)找到一个明确的答案。这就是树节点的样子:
// <libstdc++>/include/bits/stl_tree.h
struct _Rb_tree_node_base {
typedef _Rb_tree_node_base* _Base_ptr;
_Rb_tree_color _M_color;
_Base_ptr _M_parent;
_Base_ptr _M_left;
_Base_ptr _M_right;
// ...
}
因此,每个节点都包含一种颜色,以及指向其父节点及其左右子节点的指针。增量实现为:
// <libstdc++>/include/bits/stl_tree.h
struct _Rb_tree_iterator {
_Self& operator++() {
_M_node = _Rb_tree_increment(_M_node);
return *this;
}
// ...
private:
_Base_ptr _M_node;
};
实际增量不再在公共标头中,而是在库的编译部分:
// <libstdc++>/src/c++98/tree.cc
static _Rb_tree_node_base* local_Rb_tree_increment(_Rb_tree_node_base* __x) throw ()
{
if (__x->_M_right != 0) {
__x = __x->_M_right;
while (__x->_M_left != 0)
__x = __x->_M_left;
} else {
_Rb_tree_node_base* __y = __x->_M_parent;
while (__x == __y->_M_right) {
__x = __y;
__y = __y->_M_parent;
}
if (__x->_M_right != __y)
__x = __y;
}
return __x;
}
因此,最终,它是树遍历的教科书式实现:迭代器持有一个指向"当前"节点的指针,为了到达下一个节点,只要它来自正确的子节点,它就会在树中向上移动。如果它来自左子节点,它将下降到右子节点的最左边的子节点。
迭代器执行〔按顺序深度优先的树遍历〕。1这通常在递归算法中实现。由于迭代器的使用不能递归实现,因此迭代器在内部保留一个它所在位置的堆栈,以便它可以返回树。
更新:感谢Chris Dodd指出RB树节点有指向其父节点的指针,因此迭代器可以简单地跟随这些指针到下一个元素。
相关文章:
- 保持排序的数据结构,允许log N插入时间,并且可以返回我在log N中查找的元素的索引
- C++ 合并排序返回原始向量
- 算法中的排序函数返回错误
- 排序函数未正确返回数组
- 合并排序返回错误的值
- 从排序的数字数组中返回数字范围的最快方法是什么?
- 使用霍尔分区方案的快速排序算法返回原始未排序列表
- (C++)如何创建一个函数来接收两个排序的链表并返回出现在两个列表中的第三个元素列表
- 合并排序 - 返回新数组,而不是将合并的数组复制到输入数组
- 为什么我的选择排序返回原始向量中不在的值
- 如何按值对**boost::unorderede_map**进行排序,并按该顺序仅返回键
- c++std::使用函数返回值对std::向量进行排序
- 为什么一位数组返回零?合并排序测试
- 返回指向排序列表的指针;C++中的链表
- 为什么我的合并排序实现返回奇怪的数字
- 当前尝试使用气泡排序对数组进行排序,然后获取平均值,但返回的平均值是错误的
- std::使用个人类排序返回分段错误
- 不知道如何从气泡排序函数返回值
- 如何在std::map上迭代返回基于键值排序的元素
- 对std::集进行迭代是如何返回排序结果的