0

我做了半个程序来做一些主要的浮点数学运算。根据它开始的数据,它可以生成描述线段的非常大的数组。这些线段的位置是用笛卡尔坐标系记录的,用浮点数记录线段各端的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 倍,我可能只需要忍受混乱的数据并让下一个函数足够聪明以忽略它。然而,现在标记坏行将非常有用,因为下一个函数足够复杂,因为它没有试图补偿我的数据中的重复项。

4

2 回答 2

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 个独立数组,其中单个structs 数组会更简单、更高效),那么对索引数组进行排序而不是对实际数据进行排序会更容易(另外,如果您不想更改实际数据的顺序,它可能更有效,甚至是唯一可行的可能性)。用从 0 到 的数字初始化一个整数数组lines-1;然后,您可以使用该qsort函数进行排序,传递您的自定义比较器函数。

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

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


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

于 2013-10-14T01:38:01.780 回答
0

你的算法是N^2。您应该可以在N log N. 但是,获取所需的复杂性N log N在某种程度上取决于您的数据。

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

  1. 对于每个线段,如果需要,将其翻转以使 X < Q。 - 这是 O(N)。
  2. 按 X 对所有线段进行排序 - 这是 O(N log N)。
  3. 重复项现在将相邻,因此简单的扫描可以将它们删除。

这不是 100% 正确的,但大致正确 - 你需要处理一些退化的情况..

  1. 你在翻转阶段做什么是X==Q。(Ans. 基于 Y/Q 翻转。如果也相等,则使用 Z/S)
  2. 如果两个段在排序阶段有相同的 X,你会怎么做。(Ans. 按顺序使用 Y、Z、Q、R、S 作为辅助键。)
于 2013-10-14T01:37:45.500 回答