如果我有像
这样的结构std::map<string, int> myMap;
myMap["banana"] = 1;
myMap["apple"] = 1;
myMap["orange"] = 1;
如何访问myMap [0]?
我知道地图在内部进行排序,我对此很好,我希望通过索引在地图中获取值。我已经尝试了myMap [0]但是我得到了错误:
Error 1 error C2679: binary '[' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion)
我意识到我可以做这样的事情:
string getKeyAtIndex (int index){
map<string, int>::const_iterator end = myMap.end();
int counter = 0;
for (map<string, int>::const_iterator it = myMap.begin(); it != end; ++it) {
counter++;
if (counter == index)
return it->first;
}
}
但这肯定是非常低效的?有没有更好的办法?
答案 0 :(得分:22)
您的map
不应该以这种方式访问,它由键而不是位置索引。 map
迭代器是双向的,就像list
一样,因此您使用的函数不比按位置访问list
效率低。您可以使用std::advance( iter, index )
从begin()
开始的帮助来编写您的函数。如果您希望按位置随机访问,请使用vector
或deque
。
答案 1 :(得分:4)
上一个答案(见评论):仅myMap.begin();
您可以使用矢量后备存储来实现随机访问映射,后者实际上是一对矢量。当然,您当然会失去标准库映射的所有好处。
答案 2 :(得分:4)
可能有实现特定(非便携)方法来实现您的目标,但不是可移植的方法。
通常,std::map
实现为一种二叉树,通常按键排序。第一个元素的定义因顺序而异。另外,在你的定义中,元素[0]是树顶部的节点还是最左边的叶子节点?
许多二叉树被实现为链表。大多数链接列表不能像数组一样直接访问,因为要查找元素5,您必须按照链接进行操作。这是定义。
您可以同时使用std::vector
和std::map
:
std::map
。std::vector
所需的位置
在 std::map
将允许一种有效的方法来按键访问对象
std::vector
将允许通过索引访问对象的有效方法。
存储指针只允许对象的一个实例,而不必维护多个副本。
答案 3 :(得分:3)
通过比较访问向量或数组中的项具有复杂度O(1)(常数计算复杂度,单个操作)。
考虑到地图在内部实现为红黑树(或avl树,它取决于实现),每次插入,删除和查找操作都是O(log n)最坏的情况(它需要在base 2操作中以对数为单位)在树中找到一个元素,这是非常好的。
您可以处理的方法是使用包含矢量和地图的自定义类。 类末尾的插入将平均为O(1),按名称查找将为O(log n),按索引查找将为O(1),但在这种情况下,删除操作将为O(n)。 / p>
答案 4 :(得分:2)
std::map
是一个有序的容器,但是它的迭代器不支持随机访问,而是双向访问。因此,您只能通过导航其所有先前元素来访问第n个元素。您的示例的一个简短替代方法是使用标准迭代器库:
std::pair<const std::string, int> &nth_element = *std::next(myMap.begin(), N);
这具有线性复杂度,如果您打算在大型地图中经常使用这种方式,则不太理想。
一种替代方法是使用支持随机访问的有序容器。例如,boost::container::flat_map
提供了一个成员函数nth
,它使您可以精确地找到所需的内容。
答案 5 :(得分:1)
你可以使用像容器这样的其他地图
保持大小字段可以使二叉搜索树易于随机访问
这是我的实施......
标准样式,随机访问迭代器...
大小平衡树...
https://github.com/mm304321141/zzz_lib/blob/master/sbtree.h
和B +树......
https://github.com/mm304321141/zzz_lib/blob/master/bpptree.h