C++ 在地图上迭代

C++ 在地图上迭代,c++,map,iteration,C++,Map,Iteration,在这个问题上,我不是问怎么做,而是问怎么做。 我正在尝试(作为练习)实现简单的映射,虽然我在实现链接和它们的行为(如何找到下一个插入新链接的位置等)方面没有问题,但我一直在解决如何在映射上实现迭代的问题。当您仔细考虑并查看std::map时,这个map能够返回开始和结束迭代器。怎么用?特别是结束? 如果地图是一棵树,你怎么能说这张地图的哪个分支是终点?我就是不明白。如何在地图上迭代?从树顶开始,然后呢?去把所有的东西都列在左边?但左侧的节点也有到右侧的链接。我真的不知道。如果有人能给我解释一下,

在这个问题上,我不是问怎么做,而是问怎么做。
我正在尝试(作为练习)实现简单的映射,虽然我在实现链接和它们的行为(如何找到下一个插入新链接的位置等)方面没有问题,但我一直在解决如何在映射上实现迭代的问题。当您仔细考虑并查看std::map时,这个map能够返回开始和结束迭代器。怎么用?特别是结束?

如果地图是一棵树,你怎么能说这张地图的哪个分支是终点?我就是不明白。如何在地图上迭代?从树顶开始,然后呢?去把所有的东西都列在左边?但左侧的节点也有到右侧的链接。我真的不知道。如果有人能给我解释一下,或者给我一个链接,让我读一下,我会非常高兴的

出于排序目的,映射的行为类似于已排序的键/值容器(又称字典);可以将其视为键/值对的排序集合,这正是查询迭代器时得到的结果。注意:

map<string, int> my_map;
my_map["Hello"] = 1;
my_map["world"] = 2;
for (map<string, int>::const_iterator i = my_map.begin(); i != my_map.end(); ++i)
    cout << i->first << ": " << i->second << endl;
映射我的地图;
我的地图[“你好”]=1;
我的地图[“世界”]=2;
for(map::const_iterator i=my_map.begin();i!=my_map.end();++i)

cout first地图迭代器的表示完全由您决定。我认为使用单个包装指针指向
节点就足够了。例如:

template <typename T>
struct mymapiterator
{
  typename mymap<T>::node * n;
};
模板
结构mymapiterator
{
typename mymap::node*n;
};
或者类似的东西。现在,
mymap::begin()
可以返回这样一个迭代器实例,
n
将指向最左边的节点
mymap::end()
可以返回实例,其中
n
可能指向根节点或其他一些特殊节点,从这些节点可以返回到最右边的节点,以便它可以满足来自end迭代器的双向迭代


在节点之间移动的操作(
operators++()
operator-->
等)是关于从较小的值到较大的值遍历树,反之亦然。您可能已经在插入操作实现期间实现的操作。

使用二进制搜索树实现
映射。为了满足复杂性要求,它必须是一个自平衡树,因此通常使用红黑树,但这并不影响在树上迭代的方式

要按从最小到最大的顺序从二叉搜索树中读取元素,需要按顺序遍历树。递归实现非常简单,但在迭代器中使用并不实际(迭代器必须在内部维护堆栈,这会使复制成本相对较高)

您可以实现迭代顺序遍历。这是一个从我不久前编写的树容器库中获取的实现
NodePoint
是指向节点的指针,其中节点具有
left
right
parent
类型的指针

// Gets the next node in an in-order traversal of the tree; returns null
// when the in-order traversal has ended
template <typename NodePointerT>
NodePointerT next_inorder_node(NodePointerT n)
{
    if (!n) { return n; }

    // If the node has a right child, we traverse the link to that child
    // then traverse as far to the left as we can:
    if (n->right_)
    {
        n = n->right_;
        while (n->left_) { n = n->left_; }
    }
    // If the node is the left node of its parent, the next node is its
    // parent node:
    else if (n->parent_ && n == n->parent_->left_)
    {
        n = n->parent_;
    }
    // Otherwise, this node is the furthest right in its subtree; we 
    // traverse up through its parents until we find a parent that was a
    // left child of a node.  The next node is that node's parent.  If 
    // we have reached the end, this will set node to null:
    else
    {
        while (n->parent_ && n == n->parent_->right_) { n = n->parent_; }
        n = n->parent_;
    }
    return n;
}
//获取树的顺序遍历中的下一个节点;返回空值
//当顺序遍历结束时
模板
nodePost下一个\u顺序\u节点(nodePost n)
{
如果(!n){返回n;}
//如果节点有一个正确的子节点,我们将遍历指向该子节点的链接
//然后尽可能向左移动:
如果(n->右)
{
n=n->右;
而(n->left_){n=n->left_;}
}
//如果该节点是其父节点的左侧节点,则下一个节点是其父节点
//父节点:
否则,如果(n->parent\u&&n==n->parent\u->left\u)
{
n=n->父项;
}
//否则,该节点是其子树中最右边的;我们
//向上遍历它的父对象,直到找到一个
//节点的左子节点。下一个节点是该节点的父节点。如果
//我们已到达终点,这将节点设置为空:
其他的
{
而(n->parent\uu&&n==n->parent\uu->right{n=n->parent}
n=n->父项;
}
返回n;
}
要找到
begin
迭代器的第一个节点,需要找到树中最左边的节点。从根节点开始,跟随左子节点指针,直到遇到没有左子节点的节点:这是第一个节点


对于
end
迭代器,您可以将节点指针设置为指向根节点或树中的最后一个节点,然后在迭代器中保留一个标志,指示它是一个end迭代器(
is_end_
或类似的东西)。

您可能缺少的一个大技巧是
end()
iterator不需要指向任何东西。它可以是NULL或任何其他特殊值

++
操作符在迭代器经过映射末尾时将其设置为相同的特殊值。然后一切都开始了

要实现
++
,您可能需要在每个节点中保留下一个/上一个指针,或者您可以通过将刚刚离开的节点与父节点最右侧的节点进行比较,查看是否需要步行到该父节点,从而返回树以查找下一个节点,等等


不要忘记,映射的迭代器在插入/擦除操作期间应该保持有效(只要没有擦除迭代器的当前节点)。

std::map始终作为平衡二进制实现tree@Neil,它通常实现为红黑树(仅部分平衡)@avakar我想大多数人会把RB树称为平衡树——我同意它们不是完全平衡的。这我不知道。我原以为它只是一个普通的旧键/值数组,二进制搜索将直接在数组上执行。为了进行迭代,它的行为就像一个普通的列表,所以我的主要观点仍然有效。我对文本进行了编辑,使其在内部实现方面更加正确。插入到数组中的速度太慢;将以下项目移动到需要线性时间