0

My program should print how many times each number appears in array.

OUTPUT:

Number 1 appears 2 times
Number 2 appears 5 times
Number 3 appears 1 times
Number 4 appears 3 times
Most frequent: 2

This is my output:

Number 1 appears 1 times
Number 2 appears 4 times
Number 1 appears 0 times
Number 4 appears 2 times
Number 2 appears 3 times
Number 4 appears 1 times
Number 2 appears 2 times
Number 2 appears 1 times
Number 3 appears 0 times
Number 4 appears 0 times
Number 2 appears 0 times
Most frequent: 2
#include <stdio.h>

void main() {
    int i, j, count = 0, max_count = 0, max, n;
    int arr[] = { 1, 2, 1, 4, 2, 4, 2, 2, 3, 4, 2 }, counter[1000] = { 0 };
    n = sizeof(arr) / sizeof(*arr);

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

        for (j = i + 1; j < n; j++) {
            if (arr[i] == arr[j]) {
                count++;
                counter[i]++;
            }
            if (count > max_count) {
                max = arr[j];
                max_count = count;
            }
        }
    }

    for (i = 0; i < n; i++)
        printf("Number %d appears %d times\n", arr[i], counter[i]);

    printf("Most frequent: %d\n", max);
}

Could you help me fix my code?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 2
    Hint: You don't need two loops. – dcp Mar 04 '22 at 15:28
  • @Wyck my mistake, it should start at i, or count should be = 1 at first –  Mar 04 '22 at 15:37
  • There are two problems. One, your count is off by 1, because you are counting the number of duplicates of an element, not including the element itself. The easiest way to fix that is to replace `for (j = i + 1;` with `for (j = i;`. The second one is harder: you also print the count for the second, the third, etc copies of each element. You want to skip those. I will let you figure out how, but here's a hint: if `arr[i] == arr[j]` and `i != j`, then you want to skip the `j`th element on output. You may also consider a different way to count duplicates (e.g. one where you sort the array first). – n. m. could be an AI Mar 04 '22 at 15:43

3 Answers3

0

Try this (see below). One of your main problems is that you are using counter[i] but that is using a loop index, not the actual number from the array. So you need to use counter[arr[i]]. The other problem is that you are using two nested loops, which will double up your counts.

Note: The quicksort compare function is taken from this answer.

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

int compare( const void* a, const void* b)
{
     int int_a = * ( (int*) a );
     int int_b = * ( (int*) b );

     if ( int_a == int_b ) return 0;
     else if ( int_a < int_b ) return -1;
     else return 1;
}

int main()
{
  int i, j, count = 0, max_count = 0, max, n;
  int arr[] = {1, 2, 1, 4, 2, 4, 2, 2, 3, 4, 2}, counter[1000] = {0};
  n = sizeof(arr) / sizeof(*arr);
  qsort( arr, n, sizeof(int), compare );
  for (i = 0; i < n; i++) {
    ++counter[arr[i]];
  }
  max = 0;
  for (i = 0; i < n; i++) {
    if (counter[arr[i]] > max) {
      max = arr[i];
    }
  }
  
  int seen[1000];
  memset(seen,0,sizeof seen);
  for (i = 0; i < n; i++) {
    if (seen[arr[i]])
      continue;
    seen[arr[i]] = 1;
    printf("Number %d appears %d times\n", arr[i], counter[arr[i]]);
  }
  printf("Most frequent: %d\n", max);
}

Output:

---------- Capture Output ----------
> "c:\windows\system32\cmd.exe" /c C:\Temp\temp.exe
Number 1 appears 2 times
Number 2 appears 5 times
Number 3 appears 1 times
Number 4 appears 3 times
Most frequent: 4

> Terminated with exit code 0.
dcp
  • 54,410
  • 22
  • 144
  • 164
  • I get some errors compiling it –  Mar 04 '22 at 15:40
  • @devec - It should now work in C – dcp Mar 04 '22 at 15:44
  • 2
    This is a good way if you know that all elements of your array are integers between 0 and 1000. – n. m. could be an AI Mar 04 '22 at 15:46
  • If you sort the array, there is no need for the `count` and `seen` arrays. If you remove the `qsort` call, you could still remove the `seen` array by resetting `count[arr[i]]` to `0` after outputting its value for the first occurrence. – chqrlie Mar 04 '22 at 16:12
  • @chqrlie - I believe the seen array is still needed because otherwise you would print output for the same element multiple times. For example, the value 1 appears at array indices 0 and 2; if we remove the seen array logic we would print the output information twice for value 1. – dcp Mar 04 '22 at 16:16
  • 1
    @dcp: you would print the number of occurrences only if the count is `> 0` and reset it to `0` immediately after printing the first occurrence. Each further occurrence will not be printed. If you want to keep the numbers, you could just negate the count with the same effect. – chqrlie Mar 04 '22 at 17:23
0

Another way to do the same

#include <stdio.h>

int main(void) {
    int arr[] = { 1, 2, 1, 4, 2, 4, 2, 2, 3, 4, 2 };
    
    for ( int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i ) {
        // look if this value meets above
        int j, count = 1;
        for ( j = 0; j < i; ++j )
            if ( arr[j] == arr[i] )
                break;
        // if number already counted just skip it
        if ( j < i )
            continue;
        for ( j = i + 1; j < sizeof(arr) / sizeof(arr[0]); ++j )
            if ( arr[j] == arr[i] )
                count += 1;
        printf("Number %d appears %d times\n", arr[i], count);
    }

    return 0;
}
Izya Budman
  • 107
  • 2
  • 4
0

Using an array such as int counts[1000]; is going to limit the integers you can track into the range [0, 999] (that is, greater-than or equal to 0, and less-than or equal to 999). This is fine, as long as you can guarantee each input value is within this range (or otherwise handle values outside the range).

There is no need for a nested loop; simply increment the frequency counter for your current value, and update your maximum if this new count exceeds it.

When it comes time to print: for small ranges, you can just scan it entirely for hits,

for (size_t i = 0; i < MAX_N; i++)
    if (freq[i])
        printf("Number %zu appears %d times\n", i, freq[i]);

or if performance is a concern, you can sort the array, and only print each value once by resetting the frequency afterwards. Again, you must watch for values outside the valid range.

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

#define MAX_N 1000

int low_to_high(const void *p1, const void *p2) {
    int a = *((int *) p1),
        b = *((int *) p2);

    return a == b ? 0 : a > b ? 1 : -1;
}

int main(void) {
    int input[] = { 1, 2, 1, 4, 2, 4, -5, 2, 2, 3, 4, 2, 1000 };
    size_t input_length = sizeof input / sizeof *input;

    int freq[MAX_N] = { 0 };
    int max_value, max_freq = INT_MIN;

    for (size_t i = 0; i < input_length; i++) {
        int value = input[i];

        if (value >= MAX_N || value < 0) {
            fprintf(stderr, "Stray value detected: %d\n", value);
            continue;
        }

        if (++freq[value] > max_freq) {
            max_freq = freq[value];
            max_value = value;
        }
    }

    qsort(input, input_length, sizeof *input, low_to_high);

    for (size_t i = 0; i < input_length; i++) {
        int value = input[i];

        if (value >= MAX_N || value < 0) {
            fprintf(stderr, "Stray value detected: %d\n", value);
            continue;
        }

        if (freq[value]) {
            printf("Number %d appears %d times\n", value, freq[value]);
            freq[value] = 0;
        }
    }

    printf("Most frequent: %d [%d]\n", max_value, max_freq);
}

stdout:

Number 1 appears 2 times
Number 2 appears 5 times
Number 3 appears 1 times
Number 4 appears 3 times
Most frequent: 2 [5]

stderr:

Stray value detected: -5
Stray value detected: 1000
Stray value detected: -5
Stray value detected: 1000

As we've seen, using an array limits the range of integers you can support. Data structures other than arrays can provide an alternative solution to this problem.

One suggestion would be to use a linked list, so that you can support the entire range of a signed type (in this case, [INT_MIN, INT_MAX]).

Here we add our value to the list with a count of 1 if it has not been seen, otherwise we increment the existing count.

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

struct freq {
    int value;
    int count;
    struct freq *next;
};

struct freq_list {
    struct freq *head;
};

struct freq *freq_create(int value, struct freq *next) {
    struct freq *node = malloc(sizeof *node);

    node->value = value;
    node->count = 1;
    node->next = next;

    return node;
}

int freq_list_increase(struct freq_list *list, int value)
{
    if (!list->head || list->head->value > value)
        list->head = freq_create(value, list->head);
    else {
        struct freq *node = list->head;
        struct freq *last = NULL;

        while (node && node->value < value) {
            last = node;
            node = node->next;
        }

        if (!node || node->value > value)
            last->next = freq_create(value, node);
        else
            return ++node->count;
    }

    return 1;
}

int main(void) {
    int array[] = { 1, 2, 1, 4, 2, 4, 2, 2, 3, 4, 2, -1, -1, -1273, 7473, 0, 0, -2000 };
    size_t array_length = sizeof array / sizeof *array;

    struct freq_list counts = { NULL };
    int min = INT_MAX;
    int max = INT_MIN;

    for (size_t i = 0; i < array_length; i++) {
        int val = freq_list_increase(&counts, array[i]);

        if (val < min)
            min = val;

        if (val > max)
            max = val;
    }

    for (struct freq *t = NULL, *n = counts.head; n; n = t) {
        printf("%11d appears %11d times.", n->value, n->count);

        if (n->count == min)
            printf(" (MIN)");

        if (n->count == max)
            printf(" (MAX)");

        putchar('\n');

        t = n->next;
        free(n);
    }
}

Output:

      -2000 appears           1 times. (MIN)
      -1273 appears           1 times. (MIN)
         -1 appears           2 times.
          0 appears           2 times.
          1 appears           2 times.
          2 appears           5 times. (MAX)
          3 appears           1 times. (MIN)
          4 appears           3 times.
       7473 appears           1 times. (MIN)

With this implementation, presorting your input (high-to-low) may provide performance benefits. In any case, this list will sort itself as it is built. This side effect may be desirable in situations where your input cannot be sorted ahead of time.

Oka
  • 23,367
  • 6
  • 42
  • 53