Search code examples
arrayscduplicates

Duplicate Element Elimination in C


I am given to solve this question in C (it is not graded, just a LAB exercise.):

Use a single-subscripted (one-dimensional) array to solve the following problem. Read in 10 numbers, each of which is between 10 and 100, inclusive. As each number is read, print it only if it’s not a duplicate of a number already read. Provide for the “worst case” in which all 10 numbers are different. Use the smallest possible array to solve this problem.

I want to and tried to solve this problem by using pointers and writing a removeElement function but it partially works and as I enter more than one duplicate and/or do it consequently, the output becomes more wrong. I wrote my code in separate files, so I'll add them in order. Also I want to clarify that I tried realloc function too but it didn't work either. My core algorithm is: as the duplicates come, decrease the newSize and allocate the memory to this new array that has the new size, then transfer the non-duplicated elements from the old array. I've provided a test case, too.

/* main.c */
#include <stdio.h>
#include <stdlib.h>
#include "header.h"
int main(){
   int* initialArray = NULL; /* array that takes all inputs and have duplicates */
   int* newArray = NULL; /* array that should have the non-duplicated elements only */

   int SIZE = 10;
   int newSize = SIZE;
   int input = 0;
   int locCtr = 0;

   initialArray = (int*)malloc(sizeof(int) * SIZE);
   newArray = (int*) malloc(sizeof(int) * newSize);

   printf("Welcome! Please enter your 10 numbers, between 10 and 100, inclusive! \n");
   while(locCtr < 10){
       scanf("%d", &input);
       if (input >= 10 && input <= 100) { //input istenen sınırlar içerisindeyse
           if(locCtr == 0){
               printf("Value: %d \n", input);
               initialArray[locCtr] = input;
               newArray[locCtr] = input;
               locCtr++;
           }
           else{
                if (isDuplicate(initialArray, SIZE, input) == 0){ //duplicate yoksa
                    printf("Value: %d \n", input);
                    initialArray[locCtr] = input;
                    locCtr++;
                }
                else if(isDuplicate(initialArray, SIZE, input) == 1){ //duplicate varsa
                    initialArray[locCtr] = input; //inputumuzu görebilmek için kaydediyoruz
                    newSize--;
                    newArray = removeElement(initialArray, newSize, input);
                    locCtr++;
                }
            }
        }
        else { //input sınırlar içerisinde değilse
            printf("Invalid input! Please enter your numbers in the interval of [10,100]! \n");
        }
    }
    
    printf("Your initial array is: ");
    printArray(initialArray, SIZE);

    printf("Your final array is: ");
    printArray(newArray, newSize);

    printf("Bye bye! \n");

    free(initialArray);
    free(newArray);

    return 0;
}
/* header.h */
int* removeElement(int* oldArray, int newSize, int input);
int isDuplicate(int* array, int SIZE, int input);
void printArray(int* finalArray, int SIZE);
/* functions.c */
#include <stdio.h>
#include <stdlib.h>
#include "header.h"

int* removeElement(int* oldArray, int newSize, int input){
    int* newArray = (int*)malloc(sizeof(int) * newSize);
    int j = 0; //newArray indeksi
    for(int i = 0; i < newSize; i++){
        if(oldArray[i] != 0){ //0 değilse al duplicate ise 0 yapıyor
          newArray[j] = oldArray[i];
          j++;
        }
    }
    return newArray;
}

int isDuplicate(int* array, int SIZE, int input){
    for(int i = 0; i < SIZE; i++){
        if(array[i] == input){
            printf("Duplicate found! \n");
            return 1;
        }
    }
    return 0;
}

void printArray(int* finalArray, int SIZE){
    printf("[%d ", finalArray[0]);
    for(int i = 1; i < SIZE - 1; i++){
        printf("%d ", finalArray[i]);
    }
    printf("%d] \n", finalArray[SIZE - 1]);
}

A test case:

Welcome! Please enter your 10 numbers, between 10 and 100, inclusive!
10
Value: 10
20
Value: 20
30
Value: 30
40
Value: 40
40
Duplicate found!
Duplicate found!
50
Value: 50
50
Duplicate found!
Duplicate found!
60
Value: 60
75
Value: 75
80
Value: 80
Your initial array is: [10 20 30 40 40 50 50 60 75 80]
Your final array is: [10 20 30 40 40 50 50 1128087892]
Bye bye!

Thanks for your help in advance and I am sorry if there are any mistake(s) in my question format (I couldn't find any solutions that use pointers on Stack Overflow.).


Solution

  • For such a limited number of numbers, I would suggest a simpler approach.

    • Make an array of 10 numbers where you store the already seen numbers.
    • If a number not previously seen is read, keep it in the array, otherwise, don't.

    A base implementation:

    #include <stdio.h>
    #include <stdlib.h>
    
    #define SIZE (10)
    
    int main(void) {
        int seen[SIZE]; // storage for all the unique numbers
        int idx = 0;    // index of current candidate for being stored
    
        for (int i = 0; i < SIZE; ++i) {
            // Read a number and check that it's valid. Terminate otherwise:
            if (scanf("%d", &seen[idx]) != 1 || seen[idx] < 10 || seen[idx] > 100)
                exit(1);
    
            // Check if the currently entered number has been entered before:
            bool found = false;
            for (int j = 0; j < idx; ++j) {
                if (seen[j] == seen[idx]) { // seen it before, break out
                    found = true;
                    break;
                }
            }
            if (!found) { // not seen before, print it and increase idx to store it
                printf("%d\n", seen[idx++]);
            }
        }
    }
    

    This uses as many array elements as there are possible unique values. Even with this naive algorithm we could make the array SIZE - 1 since we don't need to actually store the last number to check if it's already entered. Implementation simplicity wins over the requirement to make it as small as possible when the cost is this low.