Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

why is my comparator function not working?

I have an array with elements as [0,1,0,3,12]. I want to shift all the zeros to the end of it while maintaining the relative order of the non-zero elements. After shifting the array should look like this [1,3,12,0,0]. So to do this i wrote the following code:

#include<bits/stdc++.h>
using namespace std;
bool cmp(int a,int b){
    if(a==0) return a>b;
    else return true;
}
int main(){
    int arr[]={0,1,0,3,12};
    sort(arr,arr+5,cmp);
    for(int i:arr){
        cout<<i;
    }
    return 0;
}

i wrote this code thinking that by returning false whenever zero is placed before a non-zero element i can swap the elements but this code gives the output as [12,3,1,0,0] i.e it just sorted the elements in descending order. Can anyone explain me why is my comparator function not working? can we use comparator function to do this??

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The comparator you pass to std::sort needs to be a strict weak order. In particular, you need cmp(x, x) = false for the same value, and at most one of cmp(x, y) and cmp(y, x) to be true (which is not true for cmp(1, 2) == cmp(2, 1) == true)

What you want in your order is for all elements to be equivalent, except 0 which is greater than all other elements. This can be done with a function like this:

bool cmp(int a, int b) {
    if (a==0) {
        if (b==0) return false;  // equal
        return false;  // a is greater
    }
    if (b == 0) return true;  // `a < 0`? True, since 0 is the greatest element
    return false;  // All other elements are equivalent, not less than
}

// Simplified to
bool cmp(int a, int b) {
    return b == 0 && a != 0;
}

And then you want to use std::stable_sort to preserve the order of the equivalent elements.


However, sorting isn’t the best approach here. You can simply move all the non-zero elements forward, then fill in the back space with 0s:

void move_zeroes_to_back(int* begin, int* end) {
    int* nonzero_begin = begin;
    for (; begin != end; ++begin) {
        if (*begin != 0) *nonzero_begin++ = *begin;
        // else Don't move zero values forward
    }
    // Fill in the rest
    for (; nonzero_begin != end; ++nonzero_begin) {
        *nonzero_begin = 0;
    }
}

Where the first part of this algorithm is what std::remove does:

void move_zeroes_to_back(int* begin, int* end) {
    int* nonzero_end = std::remove(begin, end, 0);  // Remove all zero values
    std::fill(nonzero_end, end, 0);  // Replace removed zero values at the end
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading