【问题标题】:How does std::map find an element by string?std::map 如何通过字符串查找元素?
【发布时间】:2014-07-25 22:02:58
【问题描述】:

在 C++ 中,您可以使用 std::map 创建地图“容器”。

在我的例子中,键是字符串,元素是整数。 (std::map<string, int>)

我想知道的是地图如何通过使用[] 运算符检索它们的元素 用字符串。

地图是否只是将输入的字符串与我声明的元素的现有字符串键集合中的 ALL 进行比较?如果是这种情况,那么如果我需要一种从一长串字符串中检索我需要的元素的最佳方法,那肯定会显得很慢。

一种更快的按字符串索引的方法是对字符串中的每个字符使用包含 256 个相同类型的链表的链表。这意味着为了让我检索我的元素,我所要做的就是说[char 1]->[char 2]->...[char n]->element.

那里的速度将取决于字符串的长度,或者你指向下一个字符的次数。

编辑我刚才描述的这个过程被称为Trie,它不是 std::map 使用的。

如果std::map<string, element_type>不使用这个方法,那它是如何工作的呢?如果我碰巧添加了大量的键,是否值得使用?

如果我的问题不清楚,请告诉我,以便我更改。我只需要知道映射中键的数量是否会减慢访问过程,以及映射如何匹配它们的元素。

【问题讨论】:

标签: c++ string optimization map


【解决方案1】:

正如其他人所说,std::map 实现为已排序、平衡的二叉树,它的查找时间复杂度为 O(log2N)。

这实际上意味着它可以进行二进制搜索:您正在寻找的恰好是“中间”元素,按排序顺序?伟大的。但如果小于这个值,则在较小元素的子树中搜索,如果它更多,则在较大元素的子树中搜索。重复直到找到,或者您意识到该元素根本不在树中。例如:

                        my_map: 37, left/less, right/greater
                                        /            \
                                      22             68
                                     /  \           /  \
                                    11   26        47  99
                                  /  |   | \     /  |   | \
                                 5  13  24  33  39 49  78 nullptr

在这里,无论你想找到哪个数字 - 你可以看到你从比较 37 开始,然后如果它小于你检查那个根节点下的“更少”子树,如果它更多你检查“更大”子树:在最坏的情况下,您最终会在找到您的元素或意识到它不在树中之前与 4 个数字进行比较。

为了让您对此有所了解,如果您有 1000 个元素,那么最多需要大约 10 次比较(平均约 9 次)。那是因为 log2(1000) 恰好是 10 - (2^10 实际上是 1024)。每当你有大约 1000 倍的元素时,就会再进行大约 10 次比较:即 100 万个元素 => ~20 次比较,10 亿 => ~30、1 万亿 => ~40。

字符串的比较通常在事物方案中相当快,特别是如果它们很短(不到几十个字符)并且它们不仅会在最后一个或三个字符中变化。


您的建议 - 特里 - 确实可以非常快 - 它们特别适用于诸如按输入完成的提示,您一次输入一个字符并希望实时更新关于可能的比赛。但是,它们确实在各处都有单独的可能字符大小的节点 - 有时额外的内存使用和随之而来的缓存页面错误可能会使平衡倾向于std::mapstd::unordered_map(哈希表) -实施每个并比较您是否有应该关心的分析证明....

【讨论】:

    【解决方案2】:

    std::map 使用binary search tree。所以查找时间与log(n) 成正比,其中n 是地图中元素的数量。所以不,它并不慢。

    另一种将字符串映射到值的方法是hash map,这种方法通常比二叉搜索树更快,但并不总是更快。标准库也有 std::unordered_map 形式的其中之一。

    您在提案中描述的内容类似于Trie。标准库没有 Trie 类。请注意,虽然 Trie 适用于作为字符串的键的特定情况,但二叉搜索树更通用,并且只要求可以对键进行排序。 std::map 默认使用 operator< 进行此排序。

    【讨论】:

    • 谢谢,这正是我需要听到的。恐怕我无法避免在没有大量反对票的情况下提出问题。可能是我无法找到有关 std::map 的信息,或者我只是一般的研究很差。我什至不知道 Tries 是一回事。
    • @Radnyx:如果您没有 C++ 语言标准的副本,大多数 在线参考将包含标准库容器和算法的复杂性。例如,请参阅复杂性标签下的 this page for std::map::operator[]
    【解决方案3】:

    我相信std::map 被实现为一种称为红黑树的二叉搜索树。它的复杂度是log(n)

    更多详情请看这里:Why is std::map implemented as a red-black tree?

    【讨论】:

      【解决方案4】:

      不,不是将密钥与所有现有密钥进行比较。

      std::map使用一种叫做二叉搜索树的数据结构,通常是红黑树,在红黑树中查找元素是非常高效的。

      红黑树的工作原理过于宽泛,请先阅读Wikipedia

      【讨论】:

        猜你喜欢
        • 2016-08-22
        • 1970-01-01
        • 1970-01-01
        • 2016-09-25
        • 1970-01-01
        • 1970-01-01
        • 2015-05-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多