1

我有以下问题:

给定 2 个包含 N 个数字的文件,例如

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 个数字),所以花费的时间太大了。有人对提高计算速度有什么建议吗?


我还尝试通过以下方式在循环中添加中断:

 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个多小时。我怎样才能加快速度?

4

3 回答 3

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..
}
于 2013-01-09T23:29:50.313 回答
1

这里的关键是“第一个文件中的两个连续数字”。

无需执行 O(N^2) 循环。事实上,您可以使用利用以下标准的动态编程方法:

  • 数字不同

  • 对于任何一组N数字,数值都是0..N-1(这是我的假设)

  • 对于任何两个连续的数字A,并且在第一个文件中,如果您在遇到时B已经遇到过,则顺序将保留在第二个文件中。AB

请注意我对价值观的假设。如果该假设是错误的,那么您也可以使用当前被接受的 O(N^2)-ish 答案(尽管您可以构建一棵树来索引值并且最坏的情况变成 O(N.log(N) )。

如果你可以直接索引这些值,那么这个问题就变成了线性的。

于 2013-01-09T23:47:09.880 回答
0

两个长度为 N 的数组之间的反转次数是...

如果 N 为 1,则反转次数为 0
,否则为第一个数组和第二个数组的最后 N-1 个元素之间的反转次数,不包括第一个数组的第一个元素加上第一个元素的位置第二个数组中的第一个数组

递归万岁:)

#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;
}
于 2013-01-09T23:57:23.703 回答