Reputation: 13
Can someone explain why the 2 last sort function in main does not work while the first one works fine.
The program build with no error. Here is the code:
#include <iostream>
#include <vector>
#include <math.h>
#include <algorithm>
using namespace std;
bool comp (int a, int b) {
if (a % 2 == 0) { return 1; }
else { return 0; }
}
int main() {
int n; cin >> n;
int arr[n];
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
sort(arr, arr+n, comp);
int pos;
for (int i = 0; i < n; i++) {
if (arr[i] % 2 == 1) {
pos = i;
break;
}
}
vector<int> un_sorted;
for (int i = 0; i < n; i++)
{
un_sorted.push_back(arr[i]);
}
//7
//5 9 2 8 6 4 7
//4 6 8 2 5 9 7
sort(un_sorted.begin(), un_sorted.begin()+pos-1);
sort(un_sorted.begin()+pos, un_sorted.end(), greater<int>());
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
}
I was trying to separate an array into 2 part: the odds and the evens and then the even are sort ascending and the odds are sorted descending
Upvotes: 0
Views: 1375
Reputation: 132340
comp()
functionAs @AlanBirtles notes, your comp()
function does not induce an order over the elements of your un_sorted
array - which is necessary for sorting them.
Specifically,
comp(x,x)
is not false for all values of x
; so, in a sense, a value can "come before itself" in correct order of array elements.comp(x,y)
and comp(y,x)
are sometimes both true - so we can have pairs of elements each of which need to come before the other in the sort order.therefore it makes no sense to sort using your comp()
.
Looking at the std::sort()
page on cppreference, we read:
comp
- comparison function object (i.e. an object that satisfies the requirements of Compare) which returns true
if the first argument is less than (i.e. is ordered before) the second.
and as expected std::sort()
is not guaranteed to do anything meaningful given your comp()
. In fact, your program has undefined behavior, and the compiler is allowed to make the program do anything it likes. The program may crash, may be stuck in an infinite loop, or may do nothing.
std::partition()
You said you wanted to:
Well, why not do just that?
The standard library provides two algorithms you can use: std::sort
and std::partition
. Here's what the code would look like:
auto is_even = [](int x) { return x % 2 == 0; };
auto evens_end_and_odds_begin =
std::partition(std::begin(my_array), std::end(my_array), is_even);
std::sort(std::begin(my_array), evens_end_and_odds_begin, std::greater<int>{});
std::sort(evens_end_and_odds_begin, std::end(my_array), std::less<int>{});
Upvotes: 7
Reputation: 1856
The issue is that you probably assume that the range sorted by sort
includes the element that the second parameter points to, called last
in most documentations.
But ranges in c++ always excludes the element that end
points to. C++ always uses half open ranges [begin, end). In your case the element at un_sorted.begin()+pos-1
is excluded, because the first sort call sorts all elements excluding that element. The second starts with the next. You should remove the -1
from the sort call.
When thinking about iterators, indices into arrays can help understanding them. end()
is always begin() + size()
. When removing the begin
from the equation you get a range of indices: [begin, end)
is [0, size)
, note: a half open range
you sort the ranges [0, pos-1)
and [pos, size)
, pos-1
is missing. [0, pos)
are your even elements. [pos, size)
the odd elements.
Upvotes: 0
Reputation: 52621
You can achieve your objective with a single sort
call, using a clever comparison function. Something like this:
bool fancy_comparison(int a, int b) {
bool a_is_even = (a % 2 == 0);
bool b_is_even = (b % 2 == 0);
if (a_is_even != b_is_even) {
// Sort even numbers before odd ones
return a_is_even;
}
if (a_is_even) {
// Sort two even numbers ascending
return a < b;
}
// Sort two odd numbers descending
return a > b;
}
And then
sort(arr, arr+n, fancy_comparison);
Upvotes: 3