2

I am trying to create a simple program which calls on 2 functions.
The first function takes a partially filled array, loops through it and deletes any duplicate values. When a value is deleted from the array, the remaining numbers are moved backwards to fill the gap i.e. when the function is finished, all null values of the array will be together at the end.

The second function prints the updated array.

My current code is below. At present when I run my code, the console shows:
2 6 0 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460.
It should be showing:
1 2 5 6

Also, I am not sure how to move the remaining elements of the array backwards so that the null values will be together at the end.

#include <iostream>

using namespace std;

void deleteRepeats(int *arr, int arraySize, int& posUsed);
void printArray(int *arr, int arraySize);

int main()
{
    int arr[10] = { 1, 2, 2, 5, 6, 1};
    int posUsed = 6;
    int arraySize = 10;


    deleteRepeats(arr, arraySize, posUsed);
    printArray(arr, arraySize);

    return 0;
}

void deleteRepeats(int *arr, int arraySize, int& posUsed)
{
    for (int i = 0; i < arraySize; i++)
    {
        for (int j = i; j < arraySize; j++)
        {
            if (arr[i] == arr[j])
            {
                for (int k = j; k < arraySize; k++)
                {
                    arr[k] = arr[k + 1];

                }
                posUsed--;
            
            }
            else
                j++;
        }
    }
}

void printArray(int *arr, int arraySize)
{
    for (int i = 0; i < arraySize; i++)
    {
        cout << arr[i] << "  ";
    }
}
UpAndAdam
  • 4,515
  • 3
  • 28
  • 46
Craig
  • 95
  • 1
  • 2
  • 11
  • 1
    `arr` only has room for 6 elements, but you set `arraySize = 10`. You can change to `int arr[10] = { 1, 2, 2, 5, 6, 1 };` – 001 Oct 10 '18 at 13:16
  • 1
    Would there be a possibility to use `std::vector` or `std::array`? – Micha Wiedenmann Oct 10 '18 at 13:16
  • Thanks @JohnnyMopp I have corrected this. Although I have the same problem with console showing no output. Micha, my lecturer does not want us to use vectors, as we have not covered them yet – Craig Oct 10 '18 at 13:21
  • 1
    Also, `arr[k] = arr[k + 1];` will read past the end of the array when `k = arraySize - 1`. – 001 Oct 10 '18 at 13:21
  • Thank you @JohnnyMopp. I have updated my code with your corrections. – Craig Oct 10 '18 at 13:31
  • 2
    In your `for` loops you need to use `posUsed` and not `arraySize`. – 001 Oct 10 '18 at 13:39
  • I changed the 3 to posUsed. My console output is now: 2 6 0 0 0 0 0 0 0 0. While it should be 1 2 5 6 0 0 0 0 0 0 – Craig Oct 10 '18 at 13:43
  • You've modified the code since you originally posted the question. Most importantly, you modified the 2nd `for` loop. So now you end up incrementing `j` twice. – 001 Oct 10 '18 at 14:00
  • Do you need to preserve the relative order of elements in your array? For example: Input: {6, 1, 2, 2, 5, 1}, Output: the same as before, or {6, 1, 2, 5}? – pptaszni Oct 10 '18 at 14:18
  • Using algorithms -- `auto ptr = std::unique(arr, arr + arraySize); std::fill(ptr, arr + arraySize, 0);` Any reason why this cannot be accepted as an answer? Can you use the algorithm functions (which **can** work with regular arrays)? – PaulMcKenzie Oct 10 '18 at 14:31
  • @PaulMcKenzie Your code obviously cannot be accepted while it's in a comment. BTW I haven't used `std::unique` recently, but from what I know about standard library, it only implements algorithms which are efficient. So it will only delete adjacent duplicates. – anatolyg Oct 10 '18 at 14:41
  • Yes @anatolyg `std::unique` will not work in this example unless you use `std::sort` beforehand. But again - this is a solution only if order of the elements doesn't matter (still waiting for OP to confirm/deny). – pptaszni Oct 10 '18 at 14:47
  • Yes, `std::sort` will also work with arrays. So solution is 3 lines instead of 2 (if algorithms can be used) (sort, unique, fill). – PaulMcKenzie Oct 10 '18 at 14:48

9 Answers9

3

I would let the std containers to what you like to do.

  • Sort the vector
  • Use erase and unique to delete duplicates.

Here is the code

#include <vector>
#include <iostream>
#include <algorithm>

void print(const std::vector<int> &arr){
    for (const auto & i : arr){
        std::cout << i <<" ";
    }
    std::cout <<"\n";
}

int main() {
    std::vector<int> arr{1, 2, 2, 5, 6, 1};    
    print(arr);

    std::sort( arr.begin(), arr.end() );
    arr.erase( std::unique( arr.begin(), arr.end() ), arr.end() );

    print(arr);
}

Ps. Using int *arr, int arraySize is not very C++ like. Please always try to use a proper container (which almost always will be std::vector).

EDIT: I changed my answer a bit, because I found this speed comparison (and actuallty the whole question answered). What's the most efficient way to erase duplicates and sort a vector?

schorsch312
  • 5,553
  • 5
  • 28
  • 57
  • 2
    OP states in comments: _my lecturer does not want us to use vectors_ – 001 Oct 10 '18 at 14:08
  • OP cannot use standard library algorithms for that assignment. Also, in your solution the result array will be sorted, which might not be desired. Also, you do not need to use `for_each` to construct a set from vector. – pptaszni Oct 10 '18 at 14:14
  • @Ptaq666 good point. I replaced `for_each`. This enhanced the const correctness. – schorsch312 Oct 10 '18 at 14:18
  • @JohnnyMopp I have not read this comment before posting my answer. Nevertheless, teaching C++ without proper container is ihmo not the right way to do it. There is no point in still using pointers and sizes if a `std::vector` can be used. C++ should be taught as shown in `A Tour of C++` by Stroustrup. – schorsch312 Oct 10 '18 at 14:22
  • 1
    Where did the OP state that the algorithm functions couldn't be used? I see that they cannot use `vector`, but `vector` is not an algorithm function. – PaulMcKenzie Oct 10 '18 at 14:29
  • @PaulMcKenzie he stated that in the comments to the question. – schorsch312 Oct 10 '18 at 14:31
  • @schorsch312 -- Where in the comments is it stated that algorithm *functions* cannot be used? Again `vector` is not an algorithm function. STL consists of containers (which the OP says couldn't be used) and functions (which the OP has yet to say anything about). – PaulMcKenzie Oct 10 '18 at 14:32
  • @schorsch312 ok. I commented in the main thread that the algorithm functions can be used on regular arrays, so there is no need to resort to vector. But waiting for the OP to acknowledge whether that would be an acceptable answer. – PaulMcKenzie Oct 10 '18 at 14:41
2

It might be easier to imagine the algorithm having separate input and output arrays. Then, in pseudo-code:

for i = 0 to input_array_size-1
    Is input[i] equal to input[j] for any j between 0 and i-1?
    Yes - do nothing
    No - copy input[i] to output

To implement this with shared input and output, you need to have two array sizes, input_array_size and output_array_size. Then, the pseudo-code becomes

output_array_size = 0
for i = 0 to input_array_size-1
    Is array[i] equal to array[j] for any j between 0 and output_array_size-1?
    Yes - do nothing
    No:
        copy array[i] to array[output_array_size]
        Increase output_array_size

Note: it writes output where the input once was, so the check for duplicates should look at all elements that were output. For example, if your array is 1, 2, 1, 3, 5, 6, 3, then for the last 3 the accumulated output is 1, 2, 3, 5, 6, and the code should compare all these with the current element.


To simplify debugging, where it says "do nothing", you can set current element to -1. This way, if you print your array during execution (for debugging), it will be clearer which elements were removed.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
2

Given your assignment constraints (more C-like, than idiomatic C++), you can rewrite your function like this, to make it work:

void deleteRepeats(int *arr, int arraySize, int& posUsed)
{
    for (int i = 0; i < posUsed; ++i)
    {
        int duplicates = 0;
        int j = i + 1;
        // find the first duplicate, if exists
        for ( ; j < posUsed; ++j)
        {
            if ( arr[i] == arr[j] ) {
                ++duplicates;
                break;
            }
        }
        // overwrite the duplicated values moving the rest of the elements...
        for (int k = j + 1; k < posUsed; ++k)
        {
            if (arr[i] != arr[k])
            {
                arr[j] = arr[k];
                ++j;
            }
            // ...but skip other duplicates
            else
            {
                ++duplicates;    
            }
        }
        posUsed -= duplicates;
    }
    // clean up (could be limited to the duplicates only)
    for (int i = posUsed; i < arraySize; ++i)
        arr[i] = 0;
}
Bob__
  • 12,361
  • 3
  • 28
  • 42
1

there are only two changes made as you can see

1: you were traversing the whole array as you have declared a posUsed=6 variable which is because there are only 6 elements so in in loops you need to traverse in array upto posUsed index like i<posUsed j<posUsed k<posUsed

2: the second changes is in j loop j=i+1 because you don't need to compare the element of any index with element of the same index you have to compare it with elements after that index. if you compare it with same element it will be same and the program will delete that same element which results in ERROR.

onw more thing is that we don't traverse after posUsed index because after that the array is already empty/zero or null whatever you call it

and if you want to display just the non duplicated elements and not the zero's at the end of the array just add if(arr[i]==0) return; in the printArray function loop before cout statement

void deleteRepeats(int *arr, int arraySize, int& posUsed)
{
{
    for (int i = 0; i < posUsed; i++)
    {
        for (int j = i+1; j < posUsed; j++)
        {
            if (arr[i] == arr[j])
            {
                for (int k = j; k < posUsed; k++)
                {
                    arr[k] = arr[k + 1];
                    
                }
            }
        
        }
    }
}
}
cryptor
  • 17
  • 6
0

using two pointers
and if the array sorted

    int removeDuplicates(vector<int>& nums) {
        if(nums.size() == 0) return 0;
        int i = 0;

        for(int j = 1; j < nums.size(); j++)
            if(nums[j] != nums[i])  nums[++i] = nums[j];

        // return new array length
        return i + 1;
    }
//input: [1, 1, 2, 1] (arr1)
//output: 2 (returned length)
// print unique element
for(int i = 0; i < output; i++) cout << arr1[i] << '\n';
// [1, 2]
time complexity: O(N/2) -> O(N)
space complexity: O(1)
Ahmed Eid
  • 192
  • 1
  • 8
0

Removing duplicate elements from an unsorted array by O(n^2) complexity.

    for (i = 1; i < vec.size(); i++)
    {
        for (j = 0; j < i; j++)
        {
            if (vec[i] == vec[j])
            {
                vec[i] = -1; //Every duplicate element will replace by -1
            }
        }
    }

   for (i = 0; i < vec.size(); i++)
    {
        if (vec[i] != -1)
        {
            copy.push_back(vec[i]);

     /*if you are using an array then store this value into a new array.
       first, declare a new array. The new array size will be equal to the 
       previous array. Like this :
       int newArr[sizeOfPreviousArrary];
       int j = 0;
       newArr[j] = arr[i]; 
       j++;
     */

        }
    }
0

Use map or set for deleting duplicates

void removeDuplicates(int arr[], int n)
{
  
    int i;
  
    // Initialise a set
    // to store the array values
    set<int> s;
  
    // Insert the array elements
    // into the set
    for (i = 0; i < n; i++) {
  
        // insert into set
        s.insert(arr[i]);
    }
  
    set<int>::iterator it;
  
    // Print the array with duplicates removed
    cout << "\nAfter removing duplicates:\n";
    for (it = s.begin(); it != s.end(); ++it)
        cout << *it << ", ";
    cout << '\n';
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
0
#include <iostream>

using namespace std;

void removedup(int *arr, int &s)
{
    for (int i =0; i<s-1; i++)
    {
        for (int j=i+1; j<s; j++)
        {
            if (arr[i]==arr[j])
            {
                for (int k=j; k<s-1; k++)
                {
                    arr[k] = arr[k+1];
                }
                s--;
                j--;
            }
        }
    }
    for (int i=0; i<s; i++)
    {
        cout << arr [i] <<" ";
    }
    cout << endl ;
}

int main() {
    int n;
    cout << "enter the size of array" << endl;
    cin >> n;
    int *arr = new int[n];
    for (int i=0; i<n; i++)
    {
        cin >> arr [i];
    }
    for (int i=0; i<n; i++)
    {
        cout << arr[i] <<" ";
    }
    cout << endl;
    removedup(arr,n);
    return 0;
}
UpAndAdam
  • 4,515
  • 3
  • 28
  • 46
  • This C++ code is removing the duplicate elements of the entered array and giving the array with distinct elements only as output regardless whatever the size of the array and whatever the number of duplicate elements in the entered array. – Himanshu Jul 15 '23 at 15:21
-1

Removing duplicate elements from an sorted array by O(n) complexity.

for (i = 0; i < n; i++)
{
    if (arr[i] != arr[i+1]){
            vec.push_back(arr[i]);
        
        /*if you are using an array then store this value into a new array.
        first, declare a new array. The new array size will be equal to the 
        previous array. Like this :
            int newArr[sizeOfPreviousArrary];
            int j = 0;
            newArr[j] = arr[i]; 
            j++;
        */
    }
}
Shunya
  • 2,344
  • 4
  • 16
  • 28