【问题标题】:Optimizing For Loops C++优化循环 C++
【发布时间】:2018-01-03 02:16:02
【问题描述】:

我有一个小函数,它通过一个向量循环查找给定的动物并返回它的栖息地。我需要优化它,但我正在做我可以做的事情。我突然想到的三件事是size_ti++,以及我正在循环一个向量的事实。我读到size_t 非常适合具有大索引的数组。我知道pre-incrementpost-increment 更好,因为它会更改原始值而不是创建临时值并递增。但是编译器通常会优化这个小的差异。最后,我想到的最后一件事是这个向量可能是未排序的,因此会降低性能。我正在考虑按动物的物种变量对向量进行排序,然后可能将其移植到BST 中进行搜索,因为时间复杂度为O(log(n))。这是我正在使用的代码:

string GetAnimalHabitat(vector<Animal> animals, string species)
{
    for (size_t i = 0; i < animals.size(); i++)
    {
        if (animals[i].species == species)

        {
            return animals[i].habitat;
        }
    }
    return "Animal not within records.";
}

有什么我可能遗漏的东西可以改进这个功能吗?任何提示都会很棒。谢谢!

【问题讨论】:

  • 不要使用vector,使用mapunordered_map。那么你根本不需要循环。对循环进行微优化不太可能给您带来比现在更好的性能。
  • 考虑像size_t 和前后增量不值得你花时间。您需要考虑不同的数据结构。你考虑过std::map吗?
  • 这个数据排序了吗?
  • 啊,是的!一张地图。这完全掩盖了我的想法。这会让 WAY 更有意义。
  • @Jake Freeman 未知此向量是否已排序。

标签: c++ for-loop optimization vector


【解决方案1】:

std::map 肯定比在此处循环遍历矢量效果更好:

string GetAnimalHabitat(const map<string, string>& animals, const string& species)
{
    auto search = animals.find(species);
    if (search != animals.end())
        return search->second;
    return string("Animal not within records.");
}

但是,它需要先构建地图。但是构建一次就足够了,您只需要添加新的密钥对即可:

map<string, string> build_map(const vector<Animal>& animals)
{
    map<string, string> ret;
    for (const auto& x : animals)
        ret[x.species] = x.habitat;
    return ret;
}

【讨论】:

  • 为什么不通过引用传递输入?
  • @PhotometricStereo 好建议。
【解决方案2】:

您可以做的一件事是通过执行以下操作来减少调用 .size() 方法的次数:

size_t vectorSize = animals.size();
for (size_t i = 0; i < vectorSize; i++)
{
    if (animals[i].species == species)

    {
        return animals[i].habitat;
    }
}

另一个小问题是将i++ 更改为++i。这样做的目的是避免每次递增时将i 的值存储在寄存器中。

【讨论】:

  • 我非常怀疑当iint 并且递增是;s 之间的唯一操作时,任何现代编译器都不会将i++ 优化为++i >
  • 比这两个更好的是切换到基于范围的 for 循环。
  • @DanielH 基于范围的 for 循环可能看起来更简洁一些,但我怀疑编译器会为其生成更高效的代码。
  • @MarkRansom 它不会做诸如多次调用size() 或以缓慢的方式增加迭代器之类的事情,这就是这个答案所讨论的全部内容。我同意这些都是相对较小的变化,切换到基于范围的 for 循环不会有很大的改进,但是当有差异时,我希望它们比非基于范围的选项略好。
【解决方案3】:

在高层次上,您希望在每次调用此函数时停止制作向量及其所有元素的完整副本。如果您需要优化,我假设向量很大,那么为什么不传递对 const 向量的引用呢?

其次,另一个问题是向量中有多少元素会匹配你的输入字符串?如果只是几个,那么扫描整个向量会加载大量内存,只是为了查看它以确定您不需要它。由于您在第一场比赛后返回,因此可以合理地认为每个物种最多有一个,在这种情况下,关联容器会更好。

一些延迟敏感的地方将数据划分为不同的组,因此不需要“过滤”。只看你关心的那组事情,然后只处理那些。

要考虑的另一件事是,字符串比较比整数比较慢得多。您可以将物种预先散列到类中,在循环之前对物种参数进行散列,然后比较散列。如果它们相等,则比较字符串以确保它是真正的匹配。

但我猜你的大部分时间都花在复制你的输入和输出上。

【讨论】:

    【解决方案4】:

    std::unordered_map 最有意义,因为顺序并不重要

    string GetAnimalHabitat(const std::unordered_map<string, string>& animals, const string& species)
    {
        auto search = animals.find(species);
        if (search != animals.end())
            return search->second;
        return string("Animal not within records.");
    }
    

    但是,它需要先构建地图。但是构建一次就足够了,您只需为其添加新的密钥对。请注意,第一次传入一个空的 unordered_map,然后传入一个新值向量和当前地图:

    build_map(const std::vector<Animal>& animals, std::unordered_map<string_string> * ret)
    {
        for (const auto& x : animals)
            ret[x.species] = x.habitat;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-07-01
      • 2018-12-23
      • 1970-01-01
      • 1970-01-01
      • 2014-07-30
      • 2017-02-28
      • 2015-05-29
      • 2014-02-18
      • 1970-01-01
      相关资源
      最近更新 更多