【问题标题】:Fastest way of finding number of distinct elements in an array查找数组中不同元素数量的最快方法
【发布时间】:2013-12-26 16:53:09
【问题描述】:

我有一个包含整数(不一定不同)的方阵。我需要最快的方法来找到其中不同元素的数量。我试图将整数存储在一维数组中,对其进行排序,然后找到不同元素的数量......但显然,它不够快。您能推荐一个更好更快的 C 语言程序吗?

【问题讨论】:

  • 值的约束是什么?价值观是积极的吗?有上限吗?

标签: c arrays


【解决方案1】:

最快的速度很大程度上取决于您正在处理的数据、所涉及结构的大小等。

你对整数可以取的值有限制吗?如果是这样,那么保持一个由整数值索引的数组,初始化为零,以跟踪该值在矩阵中有多少个副本,这可能是最快且空间使用合理的。

如果没有,那么可能使用哈希表来做类似的事情会最快。

但无论如何,为问题提供更精确的参数会非常有帮助。

【讨论】:

  • 好吧,我最多有一个 300x300 矩阵...你建议什么方法?
  • 重新表述“值是否有界?” - 你是否有一个相当接近的最小值和最大值(例如,所有数字都在 0 到 100 之间)?
【解决方案2】:

整数值 0-99 的有界集合

矩阵大小 300 x 300

int array[100];
int i;
int j;
int n_unique = 0;

for (i=0;i<300;i++) {
    if (n_unique == 100) break;
    for  (j=0;j<300;j++) {
        if (array[mat[i][j]] == 0) {
            array[mat[i][j]] = 1;
            n_unique++;
            if (n_unique == 100) break;
         }
    }
}

算法是 O(n)

【讨论】:

    【解决方案3】:

    对于任何算法,通常都会在速度、内存和复杂性之间进行折衷。正如其他人所说,您对数据的了解越多,您制定算法的速度就越快。假设您有 1 到 100 之间的数字(例如),您将能够使用这些信息真正优化算法。

    我花时间编写了适用于任何数据集的示例算法。这假设您的集合大小足够小或者您有足够的可用内存。基本上,简短的版本是分配一个与原始二维数组一样多的元素的数组。然后循环原始数组并将唯一元素放入新数组的框中。最后统计一下新数组的元素个数:

    #include <stdio.h>      /* printf, scanf, puts, NULL */
    #include <stdlib.h>     /* srand, rand */
    #include <time.h>       /* time */
    typedef int bool;
    #define TRUE 1
    #define FALSE 0
    
    /* The actual algorithm function - finds the number of unique values */
    int NumberUniqueValues(int **array, int width, int height)
    {
      int i = 0, j = 0, k = 0, maxFilled = 0;
      bool wasFound = FALSE;
      int *newElements = malloc(sizeof(int) * width * height);
    
      for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
          wasFound = FALSE;
          for (k = 0; k < maxFilled; k++) {
            if (newElements[k] == array[i][j]) {
              wasFound = TRUE;
              break;
            }
          }
    
          if (!wasFound) newElements[maxFilled++] = array[i][j];
        }
      }
    
      /* Free space */
      free(newElements);
      return maxFilled;
    }
    
    int main ()
    {
      /* variables */
      int i = 0, j = 0;
      int originalWidth = 10;
      int originalHeight = 10;
    
      /* initialize array */
      int **originalArray = (int **)malloc(originalHeight * sizeof(int*));
      for (i = 0; i < originalHeight; i++) {
        originalArray[i] = (int *)malloc(originalWidth * sizeof(int));
      }
    
      /* initialize random seed, then fill with random values */
      srand (time(NULL));
      for (i = 0; i < originalHeight; i++) {
        for (j = 0; j < originalWidth; j++) {
          originalArray[i][j] = rand() % 100;
        }
      }
    
      printf("Number unique values: %d\n", NumberUniqueValues(originalArray, originalWidth, originalHeight));
    
      /* Free space */
      for (i = 0; i < originalHeight; i++) free(originalArray[i]);
      free(originalArray);
    
      return 0;
    }
    

    同样,对于您的情况,这可能不是最快的算法,因为我不知道所有细节,但它至少可以工作。祝你好运!

    【讨论】:

    • 这具有运行时复杂度 O(n * m),其中 n = 矩阵条目数,m = 不同条目数。如果矩阵具有非常少的不同条目,这将非常快(几乎尽可能快),但如果矩阵的条目经常不同,则会很慢。如上所述,要弄清楚如何快速解决 OP 的问题,重要的是要更多地了解该问题。
    • 完全同意。如果您注意到,我的测试用例是使用“rand()”创建的,这应该会产生大部分唯一值。
    • ai ai ai - 摆脱那个 k 循环!
    【解决方案4】:

    首先,这取决于您对待阵列的方式。如果是动态的,可以把二维数组当作一维数组使用,因为静态二维数组是一维数组,动态数组可以创建为一维数组。

    const int M = 100;
    const int N = 200;
    int **a = NULL;
    int i, j;
    
    a = (int**) malloc(M * sizeof(int*) + N * M * sizeof(int));
    a[0] = (int*)(a + M);
    for (i = 1; i < M; i++) {
        a[i] = a[0] + i * N;
    }
    //code
    free(a);
    

    a[i][j] === a[0][i*num_of_columns + j]
    

    所以,一维数组的 2 种算法

    typedef int T;
    #define EQ(a, b) ((a)==(b))
    
    void quadDiff(T *a, size_t *out_size) {
        size_t i, j;
        size_t size = *out_size;
        size_t pos = 0;
        int unique;
    
        for (i = 0; i < size; i++) {
            unique = 1;
                for (j = i; j > 0; j--) {
                    if (EQ(a[i], a[j-1])) {
                        unique = 0;
                        break;
                    }
                }
                if (unique) {
                    a[pos++] = a[i];
            }
        }
        *out_size = pos;
    }
    

    void sortDiff(T *a, size_t item_size, size_t *out_size, int (*cmp)(const void *, const void *)) {
        size_t i;
        T prev = a[0];
        size_t pos = 0;
        qsort(a, *out_size, item_size, cmp);
        for (i = 0; i < *out_size; i++) {
            if (EQ(prev, a[i])) {
                continue;
            }
            prev = a[i];
            a[pos++] = a[i];
        }
        *out_size = pos;
    }
    

    【讨论】:

      【解决方案5】:

      我会建议以下方法:

      1. 在矩阵中的值上创建一个哈希图。
      2. 返回哈希图的大小作为结果。

      这个问题的时间复杂度是创建哈希图所需的时间。这不需要任何排序,并且比您使用的方法更有效。这种方法独立于输入数据的范围,使其更通用。

      (我不擅长用 C 实现东西)我将包含一个演示该方法的 Java 代码。

      class Distinct {
           public static void main(String ar[]) {
                int size;
                int matrix[][] = new int[size][size]; 
                // POPULATE THE MATRIX BY IMPLEMENTING CUSTOM METHOD
                populate(matrix); 
                // ALGORITHM:
                HashMap<Integer,Boolean> distinct = new HashMap<Integer,Boolean>();
                for(int i=0;i<size;i++) {
                    for(int j=0;j<size;j++) {
                        distinct.put(matrix[i][j],true);
                    }
                }
                System.out.println("Number of distinct elements:"+distinct.size());
           }
      }
      

      在 C 中实现哈希映射的指针可以在这里找到:Implementing a HashMap

      我希望这会有所帮助!

      【讨论】:

      • @IceFire 它没有二次复杂度,而是线性的。两个嵌套循环并不总是意味着二次,只是说......
      猜你喜欢
      • 2022-01-15
      • 2020-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-01
      • 2012-03-22
      • 2019-07-07
      相关资源
      最近更新 更多