没有循环的整数直方图

时间:2015-03-17 18:34:29

标签: c++ algorithm stl

如果有任何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 ++程序员可能提出的要好得多。

有什么建议吗?

提前谢谢你,朱塞佩

4 个答案:

答案 0 :(得分:3)

嗯,你当然至少可以清理一下循环:

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

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

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

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

答案 1 :(得分:1)

我认为没有更有效的方法。在大多数情况下,你是正确的避免循环和偏好STL,但这只适用于更大,更复杂的循环,这些循环更难编写和维护,因此可能不是最佳的。

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

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

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

答案 2 :(得分:0)

如果你考虑一下,为了计算向量中元素的出现次数,每个元素必须至少被“访问”一次,没有避免它。

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

答案 3 :(得分:0)

您可以使用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;
}