是否有高效的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
答案 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;
}