我有一个C程序,可以找到所有可能的三角形(例如3 3 4 4 5 5 => 20个三角形,其中7个没有重复)。我设法通过将a,b,c浓缩为abc格式存储所有三角形,但是我的程序太慢了。我发现查找所有三角形的函数对1000个数字需要1.68s,并且uniq()函数也是如此。(限制为2秒):
int getTriangles(const int nosniky[], int N, int trojuhelniky[]) {
int count = 0;
tcount = 0;
// The last triangle found
int TEMP = 0;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
for (int m = j + 1; m < N; m++) {
int a = nosniky[i];
int b = nosniky[j];
int c = nosniky[m];
if (a + b > c && a + c > b && c + b > a) {
// Order a,b,c so that a<b<c
order(&a, &b);
order(&a, &c);
order(&b, &c);
count++;
// Triangle will be stored as abc, so we need to join all ints into
// one (3,3,4 => 334)
int temp = joinInts(a, b);
if (i == 0 && j == 1 && m == 2) {
// first triangle, for example a=3,b=3,c=4 => 334
TEMP = joinInts(temp, c);
tcount++;
trojuhelniky[tcount - 1] = joinInts(temp, c);
} else if (joinInts(temp, c) == TEMP) {
// This is a duplicate, ignoring this one
} else {
tcount++;
trojuhelniky[tcount - 1] = joinInts(temp, c);
// TEMP = the new last found triangle
TEMP = joinInts(temp, c);
}
}
}
}
}
// Remove remaining duplicates, 1.68s as well
int newcount = uniq(trojuhelniky, tcount);
return newcount;
}
我对输入进行排序,将“最后找到的”三角形存储在TEMP变量中,然后检查下一个是否相同,如果不相同,则下一个三角形是新的TEMP。通过这种方式,我摆脱了大部分重复项,在uniq()函数中删除了其余部分。
所以我的问题是,我该怎么做才能提高代码速度?我已经设法从6s升到3.2s,现在我被困住了。
最好的情况是在3个for循环中实时删除重复项,但是我不知道该怎么做,所以现在最好的选择是尝试优化不太好的代码:D
编辑:“三角形”是指a + b> c,b + c> c和a + c> b,因此对于输入3 3 4 4 5 5,我应该找到20种可能的组合来满足该要求。删除重复项后,结果应为7(3,3,4与4,3,3相同)。
编辑2:输入范围是3到1000个随机整数。这是uniq()函数:
int uniq(int *a, size_t len) {
size_t i, j;
qsort(a, len, sizeof(int), icmp);
for (i = j = 0; i < len; i++) {
if (a[i] == 0) {
break;
}
if (a[i] != a[j]) a[++j] = a[i];
}
return (int) j + 1;
}
输入的输出2 9 18 4 1 5 19 6 3 1 2 8
应为27。
首先请注意,如果保证输入数组已排序,则在维护时i < j < m
,您将永远不会得到(3,4,3)的组合。服用
int a = nosniky[i];
int b = nosniky[j];
int c = nosniky[m];
将产生(a,b,c)
不递减的顺序。因此,这根本不是问题。
但是,如果您的输入数据包含重复项,则可以得到重复项。例如,对于3,4,4,5
您的输入,对于(i,j,m)=(0,1,3)和(i,j,m),您将得到相同的三元组(a,b,c)=(3,4,5) )=(0,2,3)。
为避免这种情况,您只需要以一种聪明的方式增加i,j,m即可跳过重复项:if nosniky[1] == 4
andnosniky[2] == 4
您不应将其j
从1增至2,而应一直增加它,直到发现nosniky[j]
与nosniky[j-1]
(或打到j == N
)不同。
int count = 0;
..... // sort nosniky[] in ascending order here
for (int i = 0; i < N;) {
int a = nosniky[i];
for (int j = i + 1; j < N;) {
int b = nosniky[j];
for (int m = j + 1; m < N;) {
int c = nosniky[m];
if (a + b > c && a + c > b && c + b > a) {
int temp = jointInts(joinInts(a, b), c);
trojuhelniky[count] = temp;
count ++;
}
while (++m < N && nosniky[m] == c)
; // skip duplicates of the third edge
}
while (++j < N && nosniky[j] == b)
; // skip duplicates of the second edge
}
while (++i < N && nosniky[i] == a)
; // skip duplicates of the first edge
}
return count;
顺便说一句,一旦确保nosniky[]
数组已排序,就知道c
不小于a
and b
。然后,正如@pmg在评论中指出的那样,可以将三角形不等式的检验简化为第一个比较,因为肯定可以满足其余两个条件:
if (a + b > c) {
int temp = jointInts(joinInts(a, b), c);
trojuhelniky[count] = temp;
count ++;
}
如果只计算三角形就可以了,不需要收集所有三角形,则可以简化最内层的循环:
for (int m = j + 1; m < N;) {
int c = nosniky[m];
if (a + b > c) {
count ++;
}
while (++m < N && nosniky[m] == c)
; // skip duplicates of the third edge
}
遵循Michael Dorgan的评论建议,您可以通过提前终止c
已知过大的长度来终止搜索,从而节省一些时间:
for (int m = j + 1; m < N;) {
int c = nosniky[m];
if (c >= a + b) // too large
break; // skip the rest
if (a + b > c) {
count ++;
}
while (++m < N && nosniky[m] == c)
; // skip duplicates of the third edge
}
然后,下一个条件变为重言式,因为它是对前一个条件的否定,因此我们可以摆脱它:
for (int m = j + 1; m < N;) {
int c = nosniky[m];
if (c >= a + b) // too large
break; // skip the rest
count ++;
while (++m < N && nosniky[m] == c)
; // skip duplicates of the third edge
}
如果期望的值非常大N
,则还可以尝试优化c
过小的值,例如使用二进制搜索。您将需要一个二进制搜索函数,该函数需要一个数组来搜索,一定范围的索引和一个目标值,并返回等于或大于目标(或范围的右端)的第一个值的索引(位置)未找到)。
int c_minimal = b - a;
// do binary search for c_minimal
// between indices j+1 (inclusive) and N (exclusive)
int initial_m = search(nosniky, j+1, N, c_minimal);
// start from the first value big enough
for (int m = initial_m; m < N;) {
int c = nosniky[m];
if (c >= a + b) // too large
break; // skip the rest
count ++;
while (++m < N && nosniky[m] == c)
; // skip duplicates of the third edge
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句