如何在C中尽可能快地标记数组中的数据重复?

时间:2013-10-14 01:14:23

标签: c arrays performance

我做了半个程序来完成一些主要的浮点运算。根据它开始使用的数据,它可以生成描述线段的非常大的数组。使用具有浮点数的笛卡尔坐标系记录这些线段的位置,以记录线的每一端的X,Y,Z位置。我不能使用X,Y,Z作为两端,所以我使用X,Y,Z作为开始,Q,R,S作为结束。所以基本上我要做的是,标记所有相同或翻转的行,使得Q,R,S第一行等于第二行的X,Y,Z和第一行的X,Y,Z等于Q,R,S在第二行。我目前的标记技术是将X设置为-1,因为我知道没有任何一行会以负坐标结束。我不想标记两行,只是除了一行之外的所有行。这是我目前的职能:

int filter(int lines)
{
printf("Filtering...\n");
refline=0;
scanline=1;
while(refline<(lines))
    {
        if( segpointX[refline] == segpointQ[scanline] && segpointY[refline] == segpointR[scanline] && segpointZ[refline] == segpointS[scanline] && segpointQ[refline] == segpointX[scanline] && segpointR[refline] == segpointY[scanline] && segpointS[refline] == segpointZ[scanline] 
         || segpointX[refline] == segpointX[scanline] && segpointY[refline] == segpointY[scanline] && segpointZ[refline] == segpointZ[scanline] && segpointQ[refline] == segpointQ[scanline] && segpointR[refline] == segpointR[scanline] && segpointS[refline] == segpointS[scanline])
            {
                //printf("Origional: %f  %f  %f  ><  %f  %f  %f\n",segpointX[refline],segpointY[refline],segpointZ[refline],segpointQ[refline],segpointR[refline],segpointS[refline]);
                //printf("Duplicate: %f  %f  %f  ><  %f  %f  %f\n\n",segpointX[scanline],segpointY[scanline],segpointZ[scanline],segpointQ[scanline],segpointR[scanline],segpointS[scanline]);
                segpointX[scanline]=-1;
            }

         scanline++;

        if(scanline==lines+1)
            {
                refline++;
                scanline=refline+1;
            }   
    }
return(0);
}

我知道我有多少行,这就是“行”整数。这段代码完全正常,但与我的其他程序相比,它的速度非常慢。我认为必须有一种方法可以更快地做到这一点,但我不确定如何。拥有这个功能真的很遗憾,因为它会拖延我的程序的其余部分,考虑到它的所有浮点数学运算速度非常快。如果没有比这更快的3倍速度,我可能只需要使用混乱的数据并使下一个功能足够聪明以忽略它。现在标记坏线非常有用,因为下一个功能很复杂,因为它没有尝试补偿我的数据中的重复。

2 个答案:

答案 0 :(得分:2)

标记数组中重复项的经典方法是以某种方式对数组进行排序(O(N·logN)),然后在单次传递中标记/删除连续的相同元素(O(N));这具有总复杂度O(N·logN),而您的方法是O(N 2 )。

在您的情况下,所有困难归结为在您的数据点之间建立某种排序关系。

首先,我会规范化行的格式,以便以相同的方式表示等效行(相同的端点)。为此,每行比较元组(XYZ)/(QRS);如果Q小于X,则QRS与XYZ交换;如果X == Q,则检查Y和R,如果它们再与Z相等,则为S.

在此O(N)传递结束时,所有等效线具有相同的XYZQRS表示。

现在,如果您不想更改数据的表示形式(6个独立数组,其中struct的单个数组将更简单,更高效),则对索引数组进行排序会更容易而不是实际数据(也可能更高效,甚至是唯一可行的可能性,如果您不想更改实际数据的顺序)。初始化一个整数数组,其数字从0到lines-1;然后,您可以使用qsort函数进行排序,并传递自定义比较器函数。

此功能将接收要比较的索引;你将使用这些索引来访问相应的XYZ / QRS并按顺序进行比较(将第一个元素的X与第二个元素的X进行比较,如果它们相等,则转到Ys,依此类推)。在排序结束时,您的索引数组将被排序,附近有相同的项目。

现在你可以做最后的传递了:扫描索引数组,并将当前索引对应的元素与下一个索引的元素进行比较:如果它们相等,则将第一个标记为重复;否则,您要么位于重复序列的最后一项,要么您处于新序列的开头,因此您需要(至少暂时)保留此项目。由于这些项目是有序的,因此相同的项目都在一行中,因此您可以一次性标记它们。


请注意,只有当您希望完全匹配时,这才能正常工作 - 即不会考虑FP不准确性。

答案 1 :(得分:0)

您的算法为N^2。您应该可以在N log N中执行此操作。但是,到达N log N所需的复杂性将在一定程度上取决于您的数据。

假设您的数据在X方向上分布良好,我就是这样做的。

  1. 对于每个线段,如果需要,将其翻转,使得X <1。问: - 这是O(N)。
  2. 按X对所有线段进行排序 - 这是O(N log N)。
  3. 重复项现在将相邻,因此简单的扫描可以删除它们。
  4. 这不是100%正确但是得到粗糙的jist正确 - 你需要处理一些退化的情况..

    1. 你在翻转阶段做的是X == Q. (Ans.Flip基于Y / Q。如果它们相等则使用Z / S)
    2. 如果两个细分在排序阶段具有相同的X,您会怎么做? (Ans。按顺序使用Y,Z,Q,R,S作为辅助键。)