【问题标题】:I want to print the number of times an element is repeated in an array of random numbers in C我想打印一个元素在 C 中的随机数数组中重复的次数
【发布时间】:2019-01-25 13:57:00
【问题描述】:

你想显示一个随机数组的重复元素,其大小可以由用户指定。我在输出中遇到的问题是,该函数正在打印一个重复的数字,它重复的次数与它重复的次数一样多,但我只想打印一次。 这是我的代码和前者之后的输出:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
int array_size = 0;
int *my_array;
int i = 0;

printf("Enter the size of the array:\n");
scanf("%d",&array_size);

my_array = malloc(array_size * sizeof my_array[0]);
if(NULL == my_array) {
    fprintf(stderr,"MEMORY ALLOLCATION FAILED \n");
    return EXIT_FAILURE;
}

for(i=0;i<array_size;i++){
    my_array[i] = rand()%array_size;
}
printf("What's in the array:\n");
for(i = 0;i<array_size;i++){
    printf("%d ",my_array[i]);
}
printf("\n");

display_repeats(my_array, array_size);
free(my_array);
return EXIT_SUCCESS;
}

void display_repeats(int *a,int n){
int *repeats;
repeats = malloc(n * sizeof repeats[0]);
int i=0;
int j=0;
int count = 0;


for(i=0;i<n;i++){
  for(j=0;j<n;j++){

     if(a[i] == a[j]){
        count++;
    }
   }
if(count>1){
repeats[i] = count;
printf("%d occurs %d times\n",a[i],repeats[i]);
}


 count = 0;

 }

free(repeats);
}

这是我得到的输出

Enter the size of the array:
5
What's in the array:
3 1 2 0 3 
3 occurs 2 times
3 occurs 2 times

我希望“3 发生 2 次”打印一次。 请帮忙!

【问题讨论】:

  • 您的循环在第二次达到“3”时捕获 - 尝试保存您已经找到的所有元素,如果重复则忽略它们
  • @DavidWinder 你能详细说明一下吗:)?也许给我一些代码!
  • 方法是问题所在 - 您计算出现次数的次数与它们在数组中出现的次数一样多(如果出现多次)。您可以先对数组进行排序,然后嵌套循环方法将起作用,前提是您每次找到匹配项时添加一个 i++。
  • 请使用一些代码作为答案!我是 C 的新手,所以这可能对我有帮助
  • 你在课堂上学习过任何类型的排序吗?如果你这样做了,那么最好你自己实现那个位并询问你是否卡住了。

标签: c arrays linux pointers memory


【解决方案1】:

由于在你的情况下,元素的值

memset(repeats, 0, n*sizeof(repeats[0]));
for(i=0;i<n;i++){
  for(j=0;j<n;j++){
     count = repeats[a[i]];
     if(count>0)
        break;
     if(a[i] == a[j]){
        count++;
     }
  }
  repeats[a[i]] = count;

这个想法是存储每个值的计数,并在开始搜索每个新值之前检查它是否已经被计数。

【讨论】:

  • 确实,刚刚在一张纸上查了一下。
【解决方案2】:

发生的事情是您的代码意识到 3 在此块中重复了两次:

for(i=0;i<n;i++){

  for(j=0;j<n;j++){
    if(a[i] == a[j]){
    count++;
    }
  }

  if(count>1){
    repeats[i] = count;
    printf("%d occurs %d times\n",a[i],repeats[i]);
  }
}

i等于0时,它会查看数组,发现3是重复的,所以count&gt;1将是true。然后,当i 等于 4 时,count&gt;1 将再次变为true,并且您会得到双重打印。

为了解决这个问题,我将创建一个数组来存储已经被验证为重复的数字并检查它。

【讨论】:

    【解决方案3】:

    试试看:

    for(i=0;i<n-1;i++)
    {
        for(j=1;j<n;j++)
        {
    

    所以,不要将同一个元素与其自身进行比较。

    【讨论】:

      【解决方案4】:

      display_repeats() 中,您可以简单地更新 2 行并添加 3 行以使您的程序具有正确的行为。我们稍后会看到:我们可以使用 C99 语法和逗号 C 运算符优化最终代码,以编写比原始代码少得多的行数(9 行而不是 20 行!)。。。。 p>

      因此,在此答案中,您将找到如何获得具有正确行为且非常短且比您的初始代码短的最终代码:

      void display_repeats(int *a, int n) {
        for (int i = 0; i < n; i++) {
          if (a[i] == -1) continue;
          int count = 1;
          for (int j = i + 1; j < n; j++)
            if (a[i] == a[j]) count++, a[j] = -1;
          if (count > 1) printf("%d occurs %d times\n", a[i], count);
        }
      }
      

      这个想法是将与前一个匹配的每个数组值设置为 -1,就在计数增量之后。因为你不想再计算这个值了。

      所以只需执行以下操作:

      • 在您写count = 0 的两行中,将0 替换为1,因为您确定列表中的每个数字都必须至少计算一次。

        这样,您可以避免检查内部循环中 i 等于 j 的情况:它已经在计数中考虑在内。所以在内循环的开头添加if (i == j) continue;

      • 通过之前的更新,您现在可以确定当您增加计数时,在内循环中,j 不等于 i。因此,您可以在不更改数组中a[i] 的情况下更改a[j] 的值。

      • 所以,在增加计数后添加a[j] = -1;。这样,当 i 将递增以检查新值的新计数时,新计数的值不可能已经被计数。

      • 最后,您不想计算 -1 在数组中出现了多少次。但是您已经用 -1 替换了一些值。所以只需在外循环的开头添加if (a[i] == -1) continue; 即可避免计算数组中有多少-1。

      这个中间代码是:

      void display_repeats(int *a,int n) {
      int *repeats;
      repeats = malloc(n * sizeof repeats[0]);
      int i=0;
      int j=0;
      int count = 1;
      
      for(i=0; i<n; i++) {
        if (a[i] == -1) continue;
        for(j=0; j<n; j++) {
          if (i == j) continue;
          if(a[i] == a[j]) {
            count++;
            a[j] = -1;
          }
        }
        if(count > 1) {
          repeats[i] = count;
          printf("%d occurs %d times\n",a[i],repeats[i]);
        }
        count = 1;
       }
      free(repeats);
      }
      

      现在,我们可以优化这段代码了。

      首先,我们可以避免在 j a[i] == a[j]:如果发生这种情况,我们知道我们之前已经显示了 a[j] 的计数(a[j] 在大批)。因此我们可以将for (j=0; j &lt; n; j++) { 替换为for (j=i+1; j&lt;n; j++) {

      通过最后一次更新,我们知道内循环的第一行永远不会匹配:i 不能等于 j。所以我们可以删除这一行 (if (i == j) continue;)。

      请注意,repeats 数组中存储的值仅用于在 printf() 调用中获取 count 的值。因此,我们可以删除对重复数组的所有引用,并在 printf() 调用中简单地使用 count。

      现在,您可以看到我们将 count 设置为 1,两次。我们只能做一次,如果我们在主循环结束时不将其设置为 1,以准备一个新循环,而是在开始时。

      现在,请注意 i、j 和 count 具有相同的类型,因此只能使用一行来定义它们:int i = 0, j = 0, count = 1;。此外,i 和 j 在 for 循环中稍后定义,因此无需在此处定义它们的初始值。所以我们可以简单地写int i, j, count = 1;。但是 count 现在定义在外循环的开头,所以我们不需要之前定义它。所以我们只需要定义没有初始值的i、j和count:int i, j, count;

      新的中间代码是:

      void display_repeats(int *a, int n) {
        int i, j, count;
      
        for (i = 0; i < n; i++) {
          if (a[i] == -1) continue;
          count = 1;
          for(j = i + 1; j < n; j++) {
            if (a[i] == a[j]) {
              count++;
              a[j] = -1;
            }
          }
          if (count > 1) printf("%d occurs %d times\n", a[i], count);
        }
      }
      

      使用 C99 语法

      但是我们可以做更多,使用 C99 规范:我们可以使用 for 指令定义一个变量:我们可以写为for (int i = ...)。不再需要之前定义它。所以我们可以避免写int i, j, count;,我们会在第一次使用时定义它们:

      void display_repeats(int *a, int n) {
        for (int i = 0; i < n; i++) {
          if (a[i] == -1) continue;
          int count = 1;
          for(int j = i + 1; j < n; j++) {
            if (a[i] == a[j]) {
              count++;
              a[j] = -1;
            }
          }
          if (count > 1) printf("%d occurs %d times\n", a[i], count);
        }
      }
      

      使用逗号 C 运算符

      再一次,我们可以做得更好!我们可以使用逗号运算符 (,):它是一个二元运算符,它计算第一个操作数,丢弃结果,计算第二个操作数并返回它的值。使用逗号运算符,我们可以将count++; a[j] = -1; 转换为一条指令:a[j] = (count++, -1)。但是我们可以避免括号写作count++, a[i] = -1。现在,我们不需要 if 语句的块,因为只有一条指令。因此,我们可以去掉很多括号。

      最终代码为:

      void display_repeats(int *a, int n) {
        for (int i = 0; i < n; i++) {
          if (a[i] == -1) continue;
          int count = 1;
          for (int j = i + 1; j < n; j++)
            if (a[i] == a[j]) count++, a[j] = -1;
          if (count > 1) printf("%d occurs %d times\n", a[i], count);
        }
      }
      

      【讨论】:

        【解决方案5】:

        谢谢大家,我得到了上面的想法! 这是我得到的..

        #include <stdio.h>
        #include <stdlib.h>
        
        int main(void) {
         int array_size = 0;
         int *my_array;
         int i = 0;
        
         printf("Enter the size of the array:\n");
         scanf("%d",&array_size);
        
         my_array = malloc(array_size * sizeof my_array[0]);
         if(NULL == my_array) {
            fprintf(stderr,"MEMORY ALLOLCATION FAILED \n");
            return EXIT_FAILURE;
            }
        
            for(i=0;i<array_size;i++){
            my_array[i] = rand()%array_size;
              }
           printf("What's in the array:\n");
           for(i = 0;i<array_size;i++){
            printf("%d ",my_array[i]);
            }
           printf("\n");
        
          display_repeats(my_array, array_size);
          free(my_array);
          return EXIT_SUCCESS;
         }
        
         void display_repeats(int *a,int n){
           int *freq;
        
        
           freq = malloc(n * sizeof freq[0]);
           int i=0;
           int j=0;
           int count = 0;
        
           for(i=0;i<n;i++){
           freq[i] = -1;
            }
        
           for(i=0;i<n;i++){
           count = 1;
            for(j=i+1;j<n;j++){
              if(a[i]==a[j]){
                count++;
                freq[j] = 0;
               }
             }
         if(freq[i]!=0){
            freq[i] = count;
          }
        }
        for(i=0;i<n;i++){
          if(freq[i]!=1 && freq[i]!=0){
            printf("%d occurs %d times\n",a[i],freq[i]);
          }
         }
        free(freq);
        }
        

        【讨论】:

        • 我现在不在电脑附近 - 您可以简化此解决方案并避免分配频率数组 - 但如果这对您有用!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-25
        • 2011-04-21
        • 1970-01-01
        • 2019-02-26
        • 2019-07-15
        • 2021-05-03
        • 2012-06-09
        相关资源
        最近更新 更多