我有以下问题:
给出N个数字的2个文件,如
file1.dat:1,2,3,4,5,6,7,8,9,0
file2.dat:2,5,4,7,6,9,8,1,0,3
我想知道第一个文件中两个连续数字的顺序在第二个文件中的顺序发生了多少次(包含相同的数字)。例如,在文件一中,我们开始寻找1和2,在第二个文件2中,在1之前,所以订单发生了变化;在第一个文件中有9个然后是0,在第二个文件中保持这个顺序。
我写了以下程序:
#include <stdio.h>
#include <stdlib.h>
#define N 32421
int main () {
int A[N], B[N];
int i,j,k=0,count=0;
FILE *fp;
if ((fp = fopen ("file1.dat", "r")) == NULL) {
printf ("Error opening file 1\n");
exit (EXIT_FAILURE);
}
for (i = 0; i < N; i++)
fscanf (fp, "%d", &A[i]);
fclose (fp);
if ((fp = fopen ("file2.dat", "r")) == NULL) {
printf ("Error opening file 2\n");
exit (EXIT_FAILURE);
}
for (i = 0; i < N; i++)
fscanf (fp, "%d", &B[i]);
fclose (fp);
for(i=0; i<N-1; i++)
for(j=0; j<N; j++)
for(k=0 ; k<N; k++)
if(B[j]==A[i] && B[k]==A[i+1] && k < j )
count++;
printf("The number of inversion is: %d\n",count);
return 0;
}
我正在处理的文件非常大,你可以从程序的第3行看到(每个文件32421个数字),所以花费的时间太长了。有人提出任何改善计算速度的建议吗?
我还尝试以下列方式在循环中添加break:
int a;
for(i=0;i<N-1;i++){
a=0;
for(j=0;j<N;j++){
for(k=0;k<N;k++){
if(A[i]==B[j] && A[i+1]==B[k] && k<j) {
count++;
break;
a=1;
} if(A[i]==B[j] && A[i+1]==B[k] && j<k){
break;
a=1;
}
}
if(a==1){
break;
}
}
}
但它仍然需要超过5个小时。我怎样才能加快速度呢?
答案 0 :(得分:4)
for(i=0; i<N-1; i++) {
//looking for the position of B[i] in A
j=-1;
while ( A[++j] != B[i] ) {}
//now A[j] is B[i]
for (k= 0 ; k < j; k++) {
//is the next in B in a previous position in A ?
if (B[i+1] == A[k]) {
count++;
break;
}
}
}
而且,这是另一种解决方案
int pos1, pos2;
for(i=0; i<N-1; i++) {
pos2=-1;
for(j=-1; j<N && pos1 != -1 && pos2 != -1; j++) { //will stop if both are found
if (pos1 == -1 && B[i]==A[j]) pos1 = j; //found the position of a num
if (B[i+1]==A[j]) pos2 = j; //found the position of the next num
if (pos2 < pos1) {
count++;
}
}
pos1 = pos2; //useful for next loop..
}
答案 1 :(得分:1)
这里的关键是“第一个文件中有两个连续的号码”。
不需要进行O(N ^ 2)循环。实际上,您可以使用动态编程方法,使用以下标准:
数字不同
对于任何N
个数字,数字值为0..N-1
(这是我的假设)
对于第一个文件中的任意两个连续数字A
和B
,如果您在遇到A
时遇到B
,则订单会保留在第二个文件中{1}}。
请注意我对价值观的假设。如果该假设是假的,那么你也可以使用当前接受的O(N ^ 2)-ish答案(尽管你可以构建一个树来索引值,最坏情况变成O(N.log(N)) )。
如果您可以直接索引值,则此问题将变为线性。
答案 2 :(得分:0)
两个长度为N的数组之间的反转次数为......
如果N为1,则反转次数为0
否则,它是第一个数组的最后N-1个元素与第二个数组之间的反转次数,不包括第一个数组的第一个元素加上第二个数组中第一个数组的第一个元素的位置
Hooray for recursion:)
#include <stdlib.h>
#include <string.h>
static int find(int a, int *b, size_t n) {
size_t k = 0;
while (k < n) {
if (b[k] == a) return k;
k++;
}
return -1;
}
int ninversions(int *a, int *b, size_t n) {
if (n == 1) return 0;
size_t pos = find(*a, b, n);
if (pos == (size_t)-1) exit(EXIT_FAILURE);
int *newb = malloc((n - 1) * sizeof *newb);
memcpy(newb, b, pos * sizeof *b);
memcpy(newb + pos, b + pos + 1, (n - pos - 1) * sizeof *b);
int retval = pos + ninversions(a + 1, newb, n - 1);
free(newb);
return retval;
}