std::map迭代器是如何工作的
How does the std::map iterator work?
C++STL类std::map使用二进制树实现O(log(n))查找。但是对于树,迭代器的工作方式并不是很明显。++运算符在树结构中的实际含义是什么?虽然"下一个元素"的概念在数组中有一个明显的实现,但对我来说,它在树中并不那么明显。如何实现树迭代器?
对于有序遍历(可能也适用于其他遍历),如果节点中有父指针,则可以进行非递归遍历。应该可以只在迭代器中存储两个指针:你需要一个你所在位置的指示,你可能(我现在不做研究)需要一个类似于"前一个"指针的东西,这样你就可以计算出你当前的移动方向(即,我需要进入左子树,还是刚刚从中返回)。
如果我们刚刚进入节点,"Previous"很可能是类似于"parent"的;"left"(如果我们从左子树返回),"right"(如果从右子树返回)和"self"(如果返回的最后一个节点是我们自己的)。
我想添加我的两美分作为评论,但由于我无法添加,我必须添加一个答案。我一直在谷歌上搜索,很沮丧,因为我找到的所有答案,除了这些,都假设了一个堆栈或其他大小可变的数据结构。我确实找到了一些代码。这表明它可以在没有堆栈的情况下完成,但我发现它很难遵循,因此决定从第一原则着手解决这个问题。
首先要注意的是,该算法是";左贪婪";。因此,当我们从根开始时,我们立即尽可能向左走,因为最左边的节点是我们首先需要的节点。这意味着我们永远不需要考虑左子树。它已经重复了一遍。
迭代的顺序是左子树、节点、右子树。因此,如果我们位于一个给定的节点,我们知道它的左子树和节点本身已经被访问过,我们下一次应该访问右子树,如果有的话,尽可能向左。
否则,我们必须爬上树。如果我们要从一个左边的孩子转到它的父母,那么父母是下一个。(之后,我们将访问它的右侧子树,如前面所述。)
最后一种情况是当我们从一个合适的孩子变成它的父母时。那位家长已经来过了,所以我们必须再上去。事实上,我们必须继续向上走,直到我们到达树根或树,或者发现自己从左边的孩子移到了父母身边。正如我们已经看到的,在这种情况下,父节点是下一个节点。(根可能由一个空指针指示,就像在我的代码中一样,或者一些特殊的哨兵节点。)
下面的代码可以很容易地适用于STL风格的迭代器
// Go as far left from this node as you can.
// i.e. find the minimum node in this subtree
Node* Leftmost(Node* node)
{
if (node == nullptr)
return nullptr;
while (node->left != nullptr)
node = node->left;
return node;
}
// Start iterating from a root node
Node* First(Node* root)
{
return Leftmost(root);
}
// The iteration is current at node. Return the next node
// in value order.
Node* Next(Node* node)
{
// Make sure that the caller hasn't failed to stop.
assert(node != nullptr);
// If we have a right subtree we must iterate over it,
// starting at its leftmost (minimal) node.
if (node->right != nullptr)
return Leftmost(node->right);
// Otherwise we must go up the tree
Node* parent = node->parent;
if (parent == nullptr)
return nullptr;
// A node comes immediately after its left subtree
if (node == parent->left)
return parent;
// This must be the right subtree!
assert(node == parent->right);
// In which case we need to go up again, looking for a node that is
// its parent's left child.
while (parent != nullptr && node != parent->left)
{
node = parent;
parent = node->parent;
}
// We should be at a left child!
assert(parent == nullptr || node == parent->left);
// And, as we know, a node comes immediately after its left subtree
return parent;
}
考虑映射中不小于当前元素但也不是当前元素的所有元素的集合。"下一个元素"是该组元素中小于该组中所有其他元素的元素。
为了使用地图,你必须有一把钥匙。该键必须实现"小于"操作。这决定了映射的形成方式,因此查找、添加、删除、增量和减量操作是有效的。
一般来说,地图内部使用某种树。
stl_tree.h:中映射迭代器运算符++监视的标准实现
_Self&
operator++() _GLIBCXX_NOEXCEPT
{
_M_node = _Rb_tree_increment(_M_node);
return *this;
}
这里讨论了_Rb_tree_increment
的实现
- QSqlquery prepare()和bindvalue()不工作
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 使用一个考虑到std::map中键值的滚动或换行的键
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 使用 std::map 的递归堆栈分配如何工作?
- Map.find()如何工作,查看输出的组件
- 在 std::map 中使用 char* 作为键,它是如何工作的
- std::map迭代器是如何工作的
- std::map::erase(const key_type&) 比较自定义后停止工作
- c++中std::map中的compare函数如果自反为真,该如何工作?
- 自定义分配器- Microsoft std::map实现对相同的元素进行两次重新分配,GCC工作得很好
- 我如何使std::find_if和std::map使用一些boost库一起工作
- std::map<t1, t2>::erase(迭代器位置)的工作?
- C++11 : map::lower_bound 在 Linux 中无法正常工作 2 个或更少的元素
- boost::bind with qtconcurrent::map ...似乎无法使其工作