在C ++中,您可以使用std::map
创建地图“容器”。
在我的例子中,键是字符串,元素是整数。 (std::map<string, int>
)
我想知道的是地图如何使用[]
运算符检索其元素
用一根绳子。
地图是否只是将输入的字符串与其现有字符串键的 ALL 与我声明的元素进行比较?如果是这种情况,那么如果我需要一种从一长串字符串中检索我需要的元素的最佳方式,那肯定会很慢。
通过字符串索引的更快方法是为字符串中的每个字符使用256个相同类型链接列表的链接列表。这意味着为了让我能够检索我的元素,我所要做的只是说[char 1]->[char 2]->...[char n]->element.
速度将由字符串的长度决定,或者多次指向下一个字符。
编辑:我刚才描述的这个过程称为Trie,它不是std :: map使用的。
如果std::map<string, element_type>
不使用此方法,那么它是如何工作的?如果我碰巧添加了大量的密钥,是否值得使用?
如果我的问题似乎不清楚,请告诉我,以便我可以更改它。我只需要知道地图中的键数量是否会减慢访问过程,以及地图如何匹配其元素。
答案 0 :(得分:4)
std::map
使用binary search tree。因此查找时间与log(n)
成比例,其中n
是地图中元素的数量。所以不,它不慢。
将字符串映射到值的另一种方法是hash map,它通常(但不总是)比二叉搜索树更快。标准库还具有std::unordered_map
形式的其中一种。
您在提案中描述的内容类似于Trie。标准库没有Trie类。请注意,虽然Trie适用于作为字符串的键的特定情况,但二进制搜索树更为通用,并且只需要可以对键进行排序。 std::map
默认使用operator<
执行此排序。
答案 1 :(得分:3)
正如其他人所说,std::map
是作为一个有序的平衡二叉树实现的,它具有复杂度为O的查找时间(log 2 N)。
这实际上意味着它可以进行二分搜索:你正在寻找的是“中间”元素,按照排序顺序?大。但是,如果它小于那个,则在较小元素的子树中搜索,如果它更多是更大元素的子树。重复直到找到,或者您意识到该元素根本不在树中。例如:
my_map: 37, left/less, right/greater
/ \
22 68
/ \ / \
11 26 47 99
/ | | \ / | | \
5 13 24 33 39 49 78 nullptr
在这里,无论你想找到哪个数字 - 你都可以看到你从37开始比较,然后如果它少了你检查那个根节点下的“less”子树,如果它更多你检查“更大”的子树:最糟糕的是,在找到元素之前,你最终会比较4个数字,或者意识到它不在树中。
为了给你一些看法,如果你说1000个元素,那么它最多需要10次比较(平均值为~9)。这是因为log 2 (1000)碰巧大约是10 - (2 ^ 10实际上是1024)。每次你有大约1000倍的元素时,还会涉及另外10个比较:即1百万个元素=&gt; ~20个比较,10亿=&gt; ~30,1万亿=&gt; 〜40。
字符串的比较通常在事物方案中相当快,特别是如果它们很短(几十个字符以下)并且它们不仅在最后一个字符或三个字符中有所不同。
你所建议的 - 一个特里 - 确实可以非常快 - 它们特别适合像你这样完整的类型提示,你一次输入一个角色并想要实时更新在可能的比赛。但是,他们确实在整个地方都有单独的可能字符大小的节点 - 有时额外的内存使用和随之而来的缓存页面错误可能会使平衡倾向于std::map
或std::unordered_map
(a哈希表) - 实现每个并比较你是否有你应该关心的分析证明......
答案 2 :(得分:2)
答案 3 :(得分:2)
我相信std::map
是作为一种称为红黑树的二叉搜索树实现的。它的复杂性是log(n)