长阵列性能问题

时间:2011-10-26 01:35:18

标签: c++ c performance algorithm optimization

我有一组长度为175,000的char指针。每个指针指向一个长度为100的c字符串数组,每个字符都是10。我需要比较字符串之间的差异。

char* arr[175000];

到目前为止,我有两个for循环,我将每个字符串与每个其他字符串进行比较。比较函数基本上取两个c字符串并返回一个整数,即整数的差异数。

这在我的4核机器上花了很长时间。上次我离开它运行45分钟,它从未完成执行。请告知更快的解决方案或一些优化。


示例:

000010
000001
由于最后两位不匹配,

的差值为2.

在我计算差异后,我将值存储在另一个数组中

                int holder;

                for(int x = 0;x < UsedTableSpace; x++){
                    int min = 10000000;

                    for(int y = 0; y < UsedTableSpace; y++){

                        if(x != y){
                            //compr calculates difference between two c-string arrays
                            int tempDiff =compr(similarity[x]->matrix, similarity[y]->matrix);

                            if(tempDiff < min){
                                min = tempDiff;
                                holder = y;
                            }
                        }       
                    }
                    similarity[holder]->inbound++;

                }

3 个答案:

答案 0 :(得分:7)

有了更多信息,我们可能会给你更好的建议,但根据我对这个问题的理解,这里有一些想法:

  1. 由于您使用每个字符来表示1或0,因此您使用的内存比您需要使用的内存多几倍,这在缓存等方面会产生很大的性能影响。相反,使用您可以根据一系列位思考的数值来表示您的数据。
  2. 一旦你实现了#1,你可以一次抓取一个整数或一个长整数并进行按位XOR运算,最终得到一个数字,在这两个数字没有的地方都有1相同的价值观然后你可以使用the tricks mentioned here中的一些来快速计算这些位数。
  3. 在某种程度上“展开”你的循环,以避免必要的跳跃次数。例如,以下代码:

    total = total + array[i];
    total = total + array[i + 1];
    total = total + array[i + 2];
    

    ...比仅仅total = total + array[i]循环三次更快。跳转很昂贵,并且会干扰处理器的流水线操作。 更新:我应该提一下你的编译器可能已经为你做了一些 - 你可以查看编译后的代码来看看。

  4. 将您的整体数据集分成多个块,以便您充分利用缓存。将您的问题视为“正方形”,其中一个轴上的i索引和另一个轴上的j轴。如果您从一个i开始并遍历所有175000个j值,那么当您到达行尾时,您访问的第一个j值将从缓存中消失。另一方面,如果你从左上角开始并从j = 0到256,那么j轴上的大多数值仍将处于低级缓存中,因为你循环将它们与i = 0,1,2等
  5. 最后,虽然这应该不言而喻,但我想值得一提的是:确保你的编译器设置为优化!

答案 1 :(得分:4)

一个简单的优化是仅比较字符串一次。如果AB之间的差异为12,则BA之间的差异也为12.您的运行时间将减少近一半。

在代码中:

int compr(const char* a, const char* b) {
  int d = 0, i;
  for (i=0; i < 100; ++i)
    if (a[i] != b[i]) ++d;
  return d;
}

void main_function(...) {

    for(int x = 0;x < UsedTableSpace; x++){
        int min = 10000000;

        for(int y = x + 1; y < UsedTableSpace; y++){

            //compr calculates difference between two c-string arrays
            int tempDiff = compr(similarity[x]->matrix, similarity[y]->matrix);

            if(tempDiff < min){
                min = tempDiff;
                holder = y;
            }
        }
        similarity[holder]->inbound++;
    }
}

注意第二个for循环,我已经改变了起始索引。

其他一些优化是在不同的线程上运行run方法,以利用您的4个核心。

答案 2 :(得分:2)

你的目标是什么,你对它们有什么看法Hamming Distances(它们是什么样的)?例如,如果您正在寻找最近的一对或最远的一对,您可能可以获得O(n ln n)算法,而不是目前为止建议的O(n ^ 2)方法。 (在n = 175000时,n ^ 2比n nn大15000倍。)

例如,您可以通过8个4位数来表征每个100位数m,即在8个m段中设置的位数,并将得到的32位签名按升序排序。最近的一对的签名可能在排序列表中附近。如果两个数字的签名不同,则很容易降低两个数字之间的距离,从而在找到距离较远的数字时提供有效的分支绑定过程。