【问题标题】:Histogram of integer without looping没有循环的整数直方图
【发布时间】:2015-03-17 18:34:28
【问题描述】:

如果有任何 STL 算法产生与以下代码相同的结果,我正在徘徊:

std::vector<int> data;
std::vector<int> counter(N); //I know in advance that all values in data
                             //are between 0 and N-1

for(int i=0; i<data.size(); ++i)
    counter[data[i]]++;

此代码仅输出我的整数数据的直方图,预定义的 bin 大小等于 1。

我知道我应该尽可能避免循环,因为 STL 算法的等效算法比大多数 C++ 程序员可能想出的优化得更好。

有什么建议吗?

提前谢谢你,朱塞佩

【问题讨论】:

  • 不应该是counter[data[...吗?
  • 是的,应该的,谢谢。已更正...

标签: c++ algorithm stl


【解决方案1】:

好吧,你当然至少可以稍微清理一下循环:

for (auto i : data) 
    ++count[i];

可以(例如)改用std::for_each

std::for_each(data.begin(), data.end(), [&count](int i) { ++count[i]; });

...但这对我来说并没有太大的进步(如果有的话)。

【讨论】:

    【解决方案2】:

    我认为没有更有效的方法可以做到这一点。在大多数情况下,您避免循环并更喜欢 STL 是正确的,但这仅适用于更难编写和维护的更大且过于复杂的循环,因此可能不是最佳的。

    在汇编级别查看问题,计算此问题的唯一方法就是您在示例中使用的方法。由于 C/C++ 循环非常有效地转换为汇编,且不必要的开销为零,这让我相信没有 STL 函数可以比您的算法更快地执行此操作。

    有一个名为 count 的 STL 函数,但它的复杂性是线性的 ( O(n) ),因此您的解决方案也是如此。

    如果你真的想挤出每个 CPU 周期的最大值,那么可以考虑使用 C 风格的数组和一个单独的计数器变量。向量引入的​​开销几乎无法测量,但如果有的话,这是我在这里看到的唯一优化机会。并不是我会建议它,但恐怕这是你可以更快地摆脱它的唯一方法。

    【讨论】:

      【解决方案3】:

      如果您考虑一下,为了计算向量中元素的出现次数,每个元素都必须至少“访问”一次,这是无法避免的。

      像这样的简单循环已经是最有效的了。您可以尝试展开它,但这可能是您能做的最好的。 STL 与否,我怀疑是否有更好的算法。

      【讨论】:

      • 嗨!没错,您必须访问矢量数据的所有元素。我正在考虑类似于在 EIGEN 的 LAPAK 中实现的优化。例如,他们计算矩阵乘法的算法比使用普通循环获得的算法要快得多。
      【解决方案4】:

      您可以使用 for_each 和一个 lambda 函数。检查这个例子:

      #include <algorithm>
      #include <vector>
      #include <ctime>
      #include <iostream>
      const int N = 10;
      using namespace std;
      
      int main()
      {
          srand(time(0));
          std::vector<int> counter(N);
          std::vector<int> data(N);
      
          generate(data.begin(),data.end(),[]{return rand()%N;});
      
          for (int i = 0;i<N;i++)
              cout<<data[i]<<endl;
      
          cout<<endl;
      
          for_each(data.begin(),data.end(),[&counter](int i){++counter[i];});
      
          for (int i = 0;i<N;i++)
              cout<<counter[i]<<endl;
      }
      

      【讨论】:

        猜你喜欢
        • 2018-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多