Home > OS >  Ordering coordinates c
Ordering coordinates c

Time:03-31

I'm trying to order a list of coordinates in c , but it's not working. i'm using c sort function, and first ordering the x values and then the y values

if n = 9 and the coordinates:

(2,2) (2,3) (1,2) (1,3) (2,1) (1,1) (3,2) (3,3) (3,1)

the output should be:

(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3 ,3)

But for some reason, it is:

(1,1)
(1,2)
(1,3)
(2,1)
(2,2)
(2,3)
(3,2)
(3,3)
(3,1)
#include <iostream>
#include <algorithm>
using namespace std;

typedef struct{
    short x;
    short y;
} coord;

bool comparex( coord a, coord b){
    if(a.x < b.x)
        return 1;
    else return 0;
}

bool comparey(coord a, coord b){
    
    if(a.x == b.x && a.y < b.y){
        return 1;
    } else return 0;
}


int main(){
    
    
    short n;
    coord v[1001];
    
    while(cin >> n){
        for (int i=1; i<=n; i  ){
            cin >> v[i].x;
            cin >> v[i].y;
        }
        
        sort(v 1, v n, comparex);
        sort(v 1, v n, comparey);
        for (int i=1; i<=n; i  ){
            cout << v[i].x << ' ' << v[i].y << endl;
        }
                    
    }

    
    return 0;
}

CodePudding user response:

std::sort isn't stable, use stable_sort or better just use a comparator that compares both elements at once:

sort(v 1, v n, [](coord a, coord b)
{
  return std::tie(a.x, a.y) < std::tie(b.x, b.y));
});

This uses std::tie which creates a std::tuple which automatically has the expected behaviour when comparing a pair of elements.

Note that for stable_sort to work you need to change comparey to just compare y (as its name suggests it does):

bool comparey(coord a, coord b){
    return a.y < b.y;
}

Your current implementation doesn't provide a strict weak ordering so can't be used as a comparator for either sort or stable_sort.

CodePudding user response:

Your comparison is flawed:

bool comparey(coord a, coord b){
    
    if(a.x == b.x && a.y < b.y){
        return 1;
    } else return 0;
}

You always return 0 (should be false) when a.x != b.x. For example comparey({0,1}, {1,1}) == false but also comparey({1,1},{0,1}) == false.

You can use std::pair for the comparison:

bool comparey(coord a, coord b){
    return std::pair(a.x,a.y) < std::pair(b.x,b.y);
}

or use std::tie to avoid constructing the pairs:

bool comparey(coord a, coord b){
    return std::tie(a.x,a.y) < std::tie(b.x,b.y);
}

CodePudding user response:

This code invokes undefined behavior because your comparey does not satisfy the requirements of a Compare function. Specifically, the relation induced by defining equiv(a, b) to mean !comparey(a, b) && !comparey(b, a) is not transitive and therefore is not an equivalence relation.

Let a be {1, 0}.

Let b be {2, 0}.

Let c be {1, 1}.

Because 1 != 2, the following are all false: comparey(a, b), comparey(b, a), comparey(b, c) and comparey(c, b).

Therefore, equiv(a, b) and equiv(b, c) are both true. It should be the case that equiv(a, c) is true as well.

However, comparey(a, c) is true, not false. Therefore equiv(a, c) is false, when it should be true.

Therefore attempting to use comparey as a comparator for sort invokes undefined behavior.


Possible fixes:

Use a single comparison function that performs lexicographic comparison of elements.

#include <tuple>

bool compare(coord a, coord b){
    return std::tie(a.x, a.y) < std::tie(b.x, b.y);
}

Make it so that comparey only compares the y coordinate, and use stable_sort so that applying comparey won't reorder elements that have the same y coordinate but different x coordinates.

bool comparey(coord a, coordb){
    return a.y < b.y;
}

// In calling code:
#include <algorithm>

std::stable_sort(v 1, v n, comparey);
  •  Tags:  
  • c
  • Related