【问题标题】:C++ STL Map vs Vector speedC++ STL Map vs Vector 速度
【发布时间】:2011-02-04 02:04:26
【问题描述】:

在我的实验性编程语言的解释器中,我有一个符号表。每个符号由一个名称和一个值组成(该值可以是例如:字符串、int、函数等类型)。

起初我用一个向量来表示表格,并遍历符号检查给定的符号名称是否合适。

然后我虽然使用地图,在我的情况下是 map<string,symbol>,但会比一直遍历向量要好 但是

这部分有点难解释,但我会努力的。

如果在我的语言程序中第一次检索变量,当然必须找到它在符号表中的位置(现在使用向量)。如果我每次执行该行时都遍历该向量(想想一个循环),那将非常慢(就像目前一样,几乎与微软的批处理一样慢)。

所以我可以使用映射来检索变量:SymbolTable[ myVar.Name ]

但请考虑以下情况:如果第一次找到仍然使用向量的变量,我可以将其确切的整数位置存储在向量中。这意味着:下次需要它时,我的解释器知道它已被“缓存”并且不会在符号表中搜索它,而是执行SymbolTable.at( myVar.CachedPosition ) 之类的操作。

现在我的(相当难的?)问题:

  • 我应该为符号表使用向量并缓存变量在向量中的位置吗?

  • 我应该使用地图吗?为什么? [] 运算符有多快?

  • 我应该使用完全不同的东西吗?

【问题讨论】:

  • 思考一下,如果您存储变量所在的整数位置,并且之前的某个变量会被垃圾收集或删除,那么您对该整数位置缓存的计划是什么?

标签: c++ stl vector map


【解决方案1】:

映射是用于符号表的好东西。但地图的operator[] 不是。一般来说,除非您编写一些琐碎的代码,否则您应该使用映射的成员函数insert()find() 而不是operator[]operator[] 的语义有些复杂,如果您要查找的符号不在地图中,几乎可以肯定不会做您想做的事。

至于mapunordered_map 之间的选择,在实现简单的解释性语言时,性能上的差异不太可能显着。如果您使用 map,则可以保证所有当前的标准 C++ 实现都支持它。

【讨论】:

  • 要“缓存”符号,只需存储 std::map::find() 返回的迭代器,而不是 std::vector 中该符号的位置。
【解决方案2】:

你实际上有很多选择。

图书馆存在

批评者

  • 地图查找和检索需要O(log N),但项目可能分散在整个内存中,因此无法很好地使用缓存策略。
  • 向量对缓存更友好,但是除非您对其进行排序,否则您将在 find 上获得 O(N) 性能,是否可以接受?
  • 为什么不使用unordered_map?它们提供O(1) 查找和检索(尽管常数可能很高),当然适合这项任务。如果您查看 Wikipedia 在 Hash Tables 上的文章,您会发现有许多可用的策略,您当然可以选择适合您特定使用模式的一种。

【讨论】:

  • 如果你保持向量排序(插入惩罚)然后 find 将有O(log N) 性能。
  • 我的向量是排序的,如何达到O(log N)的性能?
  • @John:你需要使用二分搜索算法。在 C++ 中,这可以使用 std::lower_boundstd::upper_bound 算法来实现(任何一种都可以)。
  • @Matthieu M. 即使数据集很小(300 ~ 5000),std::vector::lower_bound 似乎也比std::map::find 慢。真是出乎意料。两个小时前我在 Ubuntu 上做了这样的测试。你怎么看?
  • @John:我认为您需要提出一个正确的问题,并展示您的代码、编译器和编译器设置等......这确实是出乎意料的。
【解决方案3】:

通常,您会使用符号表来查找给定其名称的变量,因为它出现在源代码中。在这种情况下,您只有名称可以使用,因此无法在符号表中存储变量的缓存位置。所以我想说map 是一个不错的选择。 [] 运算符花费的时间与映射中元素数量的对数成正比 - 如果结果很慢,您可以使用像 std::tr1::unordered_map 这样的哈希映射。

【讨论】:

  • 你不知道我的代码,我有一个很好的选择来存储位置,相信我
  • 然后存储一个指针(例如符号*),完全绕过容器查找。
  • 您当然可以将位置存储在您的解析树或其他一些中间表示中,但是如果您使用 map,正如 Tronic 在他/她的回答中所说,您可以做同样的事情。最大的区别只是查找变量名的时间。 (实际上,如果您想序列化您的数据结构,还会出现其他问题,但我将停止在这里推测您的代码;))
【解决方案4】:

std::map 的 operator[] 需要 O(log(n)) 时间。这意味着它非常有效,但您仍应避免一遍又一遍地进行查找。除了存储索引,也许您可​​以存储对值的引用或容器的迭代器?这避免了必须完全进行查找。

【讨论】:

    【解决方案5】:

    当大多数解释器解释代码时,他们首先将其编译成中间语言。这些中间语言通常通过索引或指针而不是名称来引用变量。

    例如,Python(C 实现)将局部变量更改为按索引引用,但全局变量和类变量使用哈希表按名称引用。

    我建议查看有关编译器的介绍性文本。

    【讨论】:

      【解决方案6】:

      std::map (O(log(n))) 或哈希表 ("amortized" O(1)) 将是首选 - 如果您确定这是一个瓶颈,请使用自定义机制。通常,使用散列或标记化输入是第一个优化。

      在分析之前,最重要的是隔离查找,以便轻松替换和分析它。


      std::map 对于少数元素可能会慢一点(但是,这并不重要)。

      【讨论】:

        【解决方案7】:

        Map 是 O(log N),所以不如数组中的位置查找快。但是确切的结果将取决于很多因素,因此最好的方法是以允许您稍后在实现之间交换的方式与容器交互。也就是写一个“查找”函数,任何合适的容器都可以高效实现,让自己切换和比较不同实现的速度。

        【讨论】:

          【解决方案8】:

          Map 的运算符 [] 为 O(log(n)),参见维基百科:http://en.wikipedia.org/wiki/Map_(C%2B%2B)

          我认为,当您经常寻找符号时,使用地图当然是正确的。也许哈希图 (std::unordered_map) 可以让你的表现更好。

          【讨论】:

            【解决方案9】:

            如果您打算使用vector 并麻烦缓存最近的符号查找结果,如果您的符号表已实现,您也可以这样做(缓存最近的查找结果)作为map(但在使用map 的情况下,缓存可能不会有很多好处)。使用map,您将拥有额外的优势,即任何非缓存符号查找都比在vector 中搜索性能更高(假设vector 未排序 - 并且保持向量排序可以如果您必须多次进行排序,则成本会很高)。

            Neil's advice; map 通常是一个很好的符号表数据结构,但您需要确保正确使用它(并且不会意外添加符号)。

            【讨论】:

              【解决方案10】:

              你说:“如果第一次找到仍然使用向量的变量,我可以用它将它的确切整数位置存储在向量中。”。

              您可以对地图执行相同操作:使用find 搜索变量并存储指向它的iterator 而不是位置。

              【讨论】:

                【解决方案11】:

                对于通过字符串键查找值,map 数据类型是合适的,正如其他用户所提到的。

                STL map 的实现通常用self-balancing trees 实现,就像red black tree 数据结构一样,它们的操作需要O(logn) 时间。

                我的建议是将表格操作代码包装在函数中,
                比如table_has(name)table_put(name)table_get(name)

                这样,如果您有经验,您可以轻松更改内部符号表表示
                运行时性能缓慢,而且您可以稍后在这些例程中嵌入缓存功能。

                【讨论】:

                  【解决方案12】:

                  地图的缩放比例会更好,这将是一项重要功能。但是,不要忘记在使用地图时,您可以(与矢量不同)获取指针和引用。在这种情况下,您可以轻松地使用地图“缓存”变量,就像矢量一样有效。在这里,地图几乎肯定是正确的选择。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2011-08-07
                    • 2011-01-16
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-06-09
                    • 2011-10-24
                    相关资源
                    最近更新 更多