我正在编写一个编程难题,我有点困惑。问题是计算二维平面上的磁盘交叉点的数量。 x始终为0,y是数组的索引。半径是元素存储在数组元素中。性能很好,元素数量少,元素少,但有大量元素,如10,000,000性能差。我目前正在使用2个嵌套for循环来处理数组。
感谢有人给予的任何帮助。我与给予我的数据结构联系在一起,无法改变它们。由于我处理整数而中心点位于同一y轴上,因此磁盘与另一个磁盘相交的计算。
以下是代码:
int number_of_intersections ( int A[], int n )
{
int base = 0;
int inc = 0;
int intersect = 0;
int maxrad = 0;
int x;
if (n>1)
{
for (base=0;base<(n-1);base++)
{
inc = base+1;
do
{
if ( inc - base <= (A[base] + A[inc]))
{
intersect ++;
if (!(intersect^10000000))
{
return -1;
}
}
inc ++;
} while (inc < n);
}
}
return intersect;
}
感谢您的时间
答案 0 :(得分:4)
你的代码闻起来像是过早优化。
去除外部if语句,因为它无论如何都不会帮助你(外部循环不会在n&lt; = 1时执行)。
删除那里的魔法常数(10000000)和(我猜)比特诡计。它很难阅读,根本不灵活(至少应该是一个常量变量),并且使用 xor 代替 == 来表达逻辑。
也许用更易于阅读的for循环来交换你的do-while循环。 (由@Philip Potter建议)
现在你的代码看起来更清晰而不慢。也许你意识到现在你已经保存了一些代码行和一些括号,你可能会删除更多。
现在有了可读代码,您终于可以使用之前隐藏的更大优化了 - 请参阅其他帖子。
注意:不要提前做聪明的优化技巧。他们不会任何好。
编辑:明确要点; - )
int number_of_intersections (int A[], int n)
{
int intersect = 0;
const int maxIntersections = 10000000;
for (int base = 0; base < n-1; base++)
{
for(int inc = base+1; inc < n; inc++)
{
if (inc - base <= A[base] + A[inc])
{
intersect ++;
if (intersect == maxIntersections) return -1;
}
}
}
return intersect;
}
答案 1 :(得分:2)
你的方法是O(n ^ 2),因为你正在测试每对光盘,因此大量光盘的速度很快。
我无法想到一种方法可以让渐近更好的表现,但是你可以进行一项优化。
说你在元素p,它有半径m。显然,位于p-m <= y <= p + m的每个盘的中心在y = m时被盘覆盖。因此,您只需要为距离更远的光盘做任何工作。
答案 2 :(得分:0)
正如评论中所指出的,这实际上是一维问题。实际上,这是一个交叉区间的问题,其中区间[x,y]对应于盘中的最低和最高x坐标x =中心 - 半径和y =中心+半径。
考虑从左到右沿x和y点移动。您可以通过保留两个指向磁盘的指针进行排序,一个用于x点,另一个用于y点。使用数据结构来跟踪当前指针下的磁盘。当您看到x点时,识别位点磁盘和所有当前磁盘之间的交叉点,然后将其设置为当前磁盘。当您看到y点时,从当前磁盘中删除该点的磁盘。