计算每个唯一编号的出现次数:算法几乎可以工作

时间:2014-03-13 21:38:47

标签: c arrays algorithm int counting

我正试图从一开始就在C中工作,并确保在继续前进之前理解每一件小事。今天,我的目标是编写一个程序,该程序将采用整数列表(假设少于50个整数),并打印一个表格,其中一侧包含唯一整数列表,另一侧表示它出现的次数。我有我的功能副本,负责计算它出现的次数。

我的函数的快速摘要:接收2个指向数组的指针,以及一个要迭代多少个整数的整数。假设:我们正在检查某些数字x的重复。在阵列的某个地方,我们击中另一个x。它递增x的计数并将x转换为0以用于以后的目的。

样品试验 输入:1 2 1 2 2 1 2 输出:1出现3次。 2出现4次。

输入:1 2 3 1 2 3 1 2 3 输出:1出现3次。 2次出现3次。 3出现3次。

输入:1 2 1 3 1 2 3 输出:1出现3次。 2出现2次。 3出现1次。

虽然该程序大部分都在工作,但我想确保它完全有效。因此,我的问题是上次审判。当它适用于其他2个输入集时,为什么3只被读取一次?

    void countOccurrences(int *list, int size, int *uniques){
for (int i = 0, t = 0; i < size; i++){
    int temp = list[i];
    if (temp == 0){                     //If the number was a repeat of another previous number
        continue;                       //skip over it and go to the next element in list
    }
    uniques[t] = 1;

    for (int j = i+1; j <= size; j++){      //this iterates through list for any repeats of temp
        if (temp == list[j]){           //All repeats of temp turn to 0
            uniques[i]++;
            list[j] = 0;
        }
    }
    t++;
}

}

3 个答案:

答案 0 :(得分:3)

这是因为,3作为最后一个数字,你将发生次数重置为1

uniques[t] = 1;

并且for循环根本没有运行,因为那是最后一个数字,你不会回顾数组。

我只想编写如下程序。给予列表的值为> = 0

for (int i = 0; i < size; i++){      //this iterates through list for any repeats of temp
            uniques[list[i]]++;
 }

对于包含任何值的列表,请使用hash table数据结构

答案 1 :(得分:2)

我不会踩踏原始数据。

高级别观点:

for each element
   if it apeared before
      increment it's count
   else
      record it's first occurence

假设您需要计算N个元素数组的内容,它不能包含超过N个不同的元素。表示计数的一种简单方法是使用一组值和计数,以及一些使用的条目(看到不同的值)。这将是一条直线:

#define N ...

struct {
         int value, cnt;
       } count[N];
int entries = 0;

您检查价值v是否已经存在:

for(k = 0; k < entries && count[k].value != v; k++)
    ;
if(k == entries) {
    /* Not found */
    count[k].value = v;
    count[k].cnt   = 1;
    entries++;
}
else {
    /* Found it */
    count[k].value++;
}

只需要用代码来包装你的数据数组......

(是的,这是非常低效的;对于严重的使用更智能/更快的结构来保持值是必需的。)

答案 2 :(得分:1)

此代码存在一些问题,我们可以通过一些更完整的测试来说明这些问题。这是一个简短的,自包含的,可编译的(在C99中)示例(参见SSCCE),其中包含一些测试和一些其他诊断结果:

#include <stdio.h>

void printArray(char *name, int *list, int size) {
    printf ("%s = {",name);
    for (int i = 0; i < size; i++) {
        printf ("%d ",list[i]);
    }
    printf ("}\n");
}

void countOccurrences(int *list, int size, int *uniques, int *values) {
    for (int i = 0, t = 0; i < size; i++) {
        int temp = list[i];
        if (temp == 0) {                     
            //If the number was a repeat of another previous number
            continue;                       
            //skip over it and go to the next element in list
        }
        uniques[t] = 1;
        values[t] = temp;

        for (int j = i+1; j <= size; j++) {      
            //this iterates through list for any repeats of temp
            if (temp == list[j]) {           
                //All repeats of temp turn to 0
                uniques[i]++;
                list[j] = 0;
            }
        }
    t++;
    }
}

void test(int *x, int size) {
    const int n = 10;
    int uniques[n],values[n];
    for (int i = 0; i < n; i++) {uniques[i] = 0; values[i] = -1; }
    countOccurrences (x,size,uniques,values);
    printArray ("uniques",uniques,sizeof(uniques)/sizeof(*uniques));
    printArray ("values ",values,sizeof(values)/sizeof(*uniques));
}

int main (int argc, char* argv[]) {
    int x1[] = {1, 2, 1, 2, 2, 1, 2};
    int x2[] = {1, 2, 3, 1, 2, 3, 1, 2, 3};
    int x3[] = {1, 2, 1, 3, 1, 2, 3};
    int x4[] = {3, 2, 1, 3, 1, 2, 3};

    test(x1,sizeof(x1)/sizeof(*x1));
    test(x2,sizeof(x2)/sizeof(*x2));
    test(x3,sizeof(x3)/sizeof(*x3));
    test(x4,sizeof(x4)/sizeof(*x4));
    return 0;
}

(感谢@Matt McNabb的建议,将公共代码重构为test()函数)

...输出为:

uniques = {3 4 0 0 0 0 0 0 0 0 }
values  = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {4 3 3 0 0 0 0 0 0 0 }
values  = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {4 2 1 1 0 0 0 0 0 0 }
values  = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 3 0 0 0 0 0 0 0 }
values  = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }

第一个测试为您提供预期的输出。第二个测试表明列表中的第一个项目有一个额外的计数。这可以通过更改:

来解决
for (int j = i+1; j <= size; j++){

for (int j = i+1; j < size; j++){

...因为代码计算超出数据末尾的一个空格。修复此错误的输出是:

uniques = {3 4 0 0 0 0 0 0 0 0 }
values  = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 3 3 0 0 0 0 0 0 0 }
values  = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 1 1 0 0 0 0 0 0 }
values  = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values  = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }

第三和第四个测试结果难以解释,因为预期的输出应该是不明显的。计数功能似乎是用于在list中找到这些数字的顺序报告唯一数字的计数。然而,在第三次测试中,第一次出现“3”是列表中的第四项。改变:

uniques[i]++;

uniques[t]++;

...表示计数作为计数列表中的t项输出,给出输出:

uniques = {3 4 0 0 0 0 0 0 0 0 }
values  = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 3 3 0 0 0 0 0 0 0 }
values  = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values  = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values  = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }

此输出现在是正确的,但如果没有我添加到代码中的uniques数组,很难解释values中的计数。请注意,在上一个测试用例中,第一个计数是3list的数量,而不是1的数量。

最后,将参数修改为的所有通常是不好的做法。有必要在C中执行此操作,因为您无法从函数返回数组,但修改uniquesvalues指向的数组通常是可以容忍的,因为它们明确可用于向外返回结果功能。但是,修改用于向函数提供输入数据的参数,countOccurrences()list执行操作通常是不明智的,因为这意味着使用countOccurrences()的代码必须复制{{ 1}}在将指向该列表的指针传递给list之前,如果它还希望将countOccurrences()的原始内容用于其他目的。

如果我们知道要计算的整数都小于或等于list数组的大小,那么@Saravana Kumar建议的函数运行起来更快,更容易纠正:< / p>

uniques