确定每个元素在数组中出现的频率?

时间:2016-01-31 04:22:10

标签: c arrays algorithm

是否有高效的C算法来计算和报告数组中相等元素的数量

例如,如果我们有

int Z[] = { 4, 9, 4, 10, 4, 2,  10, 1, 19, 21, 21 };

然后结果应该是

elem         number
  4            3
  9            1
  10           2
  2            1
  1            1
  19           1
  21           2

2 个答案:

答案 0 :(得分:2)

有很多方法可以做到这一点,每种方法都有不同的性能权衡。

首先,您可以在数组上执行双重循环,并为每个元素计算它出现的次数。这将花费时间O(n 2 ),其中n是数组元素的数量。但是,它只需要空间O(1)。

其次,您可以按升序对数组进行排序,这会将相同的元素组合在一起。从那里,很容易看出每个元素出现的次数,因为您可以遍历数组一次并计算每个元素出现的连续次数。使用的运行时和空间取决于您对数组进行排序的方式。如果使用heapsort,则运行时将为O(n log n),空间使用量仅为O(1)。如果您碰巧知道数组中从0到U的所有元素,则可以使用时间O(n + U)和空间O(U)中的计数排序或时间O(n log U)和空间中的基数排序为O(n)。

第三,您可以构建一个存储每个元素频率的辅助表,并通过在数组中迭代一次来填充它,随时填写条目。如果使用哈希表,则预期运行时将为O(n),空间使用率也将为O(n)。如果您知道数组元素在0到U(包括0和U)的范围内,您可以使用频率数组并在时间O(n + U)和空间O(U)中解决这个问题(基本上,它会计算排序! )

这里没有明显的赢家。对于具有O(1)空间使用的东西,Heapsort具有最佳时间复杂度。散列具有最佳的总体时间复杂度,但空间使用率较低。计数或基数排序可能最好,具体取决于数字的大小。

根据您的具体情况,看看您的实际参数是什么,希望您可以选择最适合您的解决方案。

答案 1 :(得分:2)

这是一个有效的答案。

第一个循环将数字数组的数量初始化为全零。

第二个循环扫描所有数字,直到它达到数字零,然后扫描停止。关于这种方法的好处是你可以添加一堆不是零的数字,以使你的数组​​更大,程序仍然可以工作。

最后,第三个循环只是遍历数字数组,并以一种很好的排序方式打印结果。

在预定义数字数组中,不要删除零并重新运行程序,否则会出现意外结果,包括分段错误。

    #include <stdlib.h>
    #include <stdio.h>
    int main(){
      int Z[] = { 4, 9, 4, 10, 4, 2,  10, 1, 19, 21, 21, 0};
      int n;
      int lowest=1;
      int highest=100;
      int counts[highest+1];
      for (n=0;n<=highest;n++){
        counts[n]=0;
      }
      int *num=Z;
      while((int)*num != 0){
        counts[*num]++;
        num++;
      }

      for (n=lowest;n<=highest;n++){
        if (counts[n] > 0){
          printf("%d = %d\n",n,counts[n]);
        }
      }
      return 0;
    }