473,698 Members | 2,005 Online

# Even-Odd sorting

Hello.

It seems a year is all it takes for one's proficiency in C++ to become
too rusty. Professionally, I've been away from the language (and from
programming in general), but I still preserve an appreciation for it.

So I decided to toy with some idea, just for fun and for evaluating how
rusty I'd become. "Let me write a simple functor for sorting the
elements of a collection! I will start with a simple collection of
integers.", I thought. I then chose an unusual criterion for the
sorting: "I'd like the elements to be ordered so that the even members
should appear before the odd ones." The following is what I came up
with. The program is not producing the expected behavior and I suspect
it has to do with my predicate. It is probably not fully complying to
the requirements for such a function.

#include <iostream>
#include <set>
#include <functional>
#include <algorithm>
#include <iterator>

class EvenOddSorting {
public:
bool operator()(cons t int i, const int j) const {
return i % 2 == 0 && j % 2 != 0;
}
};

int main() {
std::set<int, EvenOddSortingi ntSet;
intSet.insert(1 0);
intSet.insert(7 );
intSet.insert(5 );
intSet.insert(1 8);
intSet.insert(3 );
std::cout << "Even-Odd ordered set: ";
std::copy(intSe t.begin(),
intSet.end(),
std::ostream_it erator<int>(std ::cout, " "));
std::cout << "\n";
}

Given the above program, the expected output should read:

Even-Odd ordered set: 10 18 3 5 7

Notice how my proposed output implies a hidden requirement of ordering
among even and odd numbers. That would be ideal, but I'd be satisfied
(at first) with an output like '18 10 5 7 3'. Would anybody care to give
me a hand?

Thank you!

--
Ney André de Mello Zunino
Jun 27 '08 #1
18 4904
Ney André de Mello Zunino wrote:
[..]
So I decided [..] "Let me write a simple functor for sorting the
elements of a collection! I will start with a simple collection of
integers.", I thought. I then chose an unusual criterion for the
sorting: "I'd like the elements to be ordered so that the even members
should appear before the odd ones." The following is what I came up
with. The program is not producing the expected behavior and I suspect
it has to do with my predicate. It is probably not fully complying to
the requirements for such a function.

#include <iostream>
#include <set>
#include <functional>
#include <algorithm>
#include <iterator>

class EvenOddSorting {
public:
bool operator()(cons t int i, const int j) const {
return i % 2 == 0 && j % 2 != 0;
What if they are both odd? What if they are both even? Does the
predicate satisfy the requirement of strict weak ordering?

The predicate returns 'true' if the first is even and the second is odd.
For the rest it would return 'false', right? That means that when
comparing 5 and 7 it would determine that 5 is not less than 7. And
when comparing 7 and 5 it would determine that 7 is not less than 5.
That seems to me that 5 is the same as 7. That is, 5 and 7 cannot
coexist in the set that has your 'EvenOddSorting ' as the predicate.

Do the same with two evens.
}
};

int main() {
std::set<int, EvenOddSortingi ntSet;
intSet.insert(1 0);
intSet.insert(7 );
After this the collection should be {10, 7}. Is it?
intSet.insert(5 );
After this the collection _could_ be 10, 5, 7, or it could be 10, 7, 5,
if the predicate allowed placing both 5 and 7 next to each other. It
does not, AFAICT. So, here the collection will be {10, 7}, still.

And so on.
intSet.insert(1 8);
intSet.insert(3 );
std::cout << "Even-Odd ordered set: ";
std::copy(intSe t.begin(),
intSet.end(),
std::ostream_it erator<int>(std ::cout, " "));
std::cout << "\n";
}

Given the above program, the expected output should read:

Even-Odd ordered set: 10 18 3 5 7
OK, that's what it *should* read (you believe). What *does* it read?
>
Notice how my proposed output implies a hidden requirement of ordering
among even and odd numbers. That would be ideal, but I'd be satisfied
(at first) with an output like '18 10 5 7 3'. Would anybody care to give
me a hand?
Not sure what kind of help you are seeking. You've not specified all
the requirements for your predicate to implement it correctly. Have I
given you enough hints to go on?

V
--
Jun 27 '08 #2

On May 23, 3:41 pm, Ney André de Mello Zunino <zun...@inf.ufs c.br>
wrote:
[snip]
I then chose an unusual criterion for the
sorting: "I'd like the elements to be ordered so that the even members
should appear before the odd ones."
[snip]
The program is not producing the expected behavior and I suspect
it has to do with my predicate.
[snip]
class EvenOddSorting {
public:
bool operator()(cons t int i, const int j) const {
return i % 2 == 0 && j % 2 != 0;
}

};
[snip]
std::set<int, EvenOddSortingi ntSet;
[snip]
std::set. Note that a set can only hold unique items. That is, no two
elements a and b exist in a set such that a == b.

Your predicate tests if a < b. If a < b OR b < a then a != b. If (NOT
a < b) AND NOT (b < a) then a == b. The set uses your predicate to
determine uniqueness. Because your predicate only compares based on
parity and not values, in effect you have defined all even numbers to
be equivalent, and all odd numbers to be equivalent. Therefore your
set, which must only contain unique values, will contain one even
number, and one odd number.

If you want the value of the integers to be a criteria for uniqueness
your predicate must take that into account. You can also, then, have
sorting "within" the even and odd numbers, if you do something like

class EvenOddValueSor ting {
public:
bool operator()(cons t int i, const int j) const {
bool i_is_even = !(i % 2);
bool j_is_even = !(j % 2);
if (i_is_even == j_is_even) // if parity is same...
return i < j; // ... compare by value only
else
return i_is_even; // ... otherwise even always < odd.
}
};

Alternatively, you can use the predicate you have now for sorting, but
do not use a container that requires value uniqueness. For example,
use a vector with your current predicate:

std::vector<int v;
v.push_back(10) ;
v.push_back(7);
v.push_back(5);
v.push_back(18) ;
v.push_back(3);
std::sort(v.beg in(), v.end(), EvenOddSorting( ));

Doing that with EvenOddSorting will place all the even numbers before
all the odd ones. Doing it with EvenOddValueSor ting will sort by
numeric value also. Note that std::sort is not stable; but you can use
std::stable_sor t if that is a requirement. See:

http://www.sgi.com/tech/stl/table_of_contents.html

Jason
Jun 27 '08 #3
Victor Bazarov wrote:
What if they are both odd? What if they are both even? Does the
predicate satisfy the requirement of strict weak ordering?

The predicate returns 'true' if the first is even and the second is odd.
For the rest it would return 'false', right? That means that when
comparing 5 and 7 it would determine that 5 is not less than 7. And
when comparing 7 and 5 it would determine that 7 is not less than 5.
That seems to me that 5 is the same as 7. That is, 5 and 7 cannot
coexist in the set that has your 'EvenOddSorting ' as the predicate.

Do the same with two evens.
Yes, I see what you mean and it makes perfect sense now.

[...]
OK, that's what it *should* read (you believe). What *does* it read?
Sorry for not posting the results. You were right, only 10 and 7 were
being accepted in the collection.
>Notice how my proposed output implies a hidden requirement of ordering
among even and odd numbers. That would be ideal, but I'd be satisfied
(at first) with an output like '18 10 5 7 3'. Would anybody care to
give me a hand?

Not sure what kind of help you are seeking. You've not specified all
the requirements for your predicate to implement it correctly. Have I
given you enough hints to go on?
Yes, sir, you have. Here's the modified functor class (which can
probably be further simplified):

class EvenOddSorting {
public:
bool operator()(cons t int i, const int j) const {
if (i % 2 == 0) {
if (j % 2 != 0) { // i is even and j is odd
return true;
} else { // both i and j are even
return i < j;
}
} else {
if (j % 2 == 0) { // i is odd and j is even
return false;
} else { // both i and j are odd
return i < j;
}
}
}
};

The program now outputs my desired results:

Even-Odd ordered set: 10 18 3 5 7

Do you see any remaining issue?

Thank you,

--
Ney André de Mello Zunino
Jun 27 '08 #4
ja************@ gmail.com wrote:

[...]
class EvenOddValueSor ting {
public:
bool operator()(cons t int i, const int j) const {
bool i_is_even = !(i % 2);
bool j_is_even = !(j % 2);
if (i_is_even == j_is_even) // if parity is same...
return i < j; // ... compare by value only
else
return i_is_even; // ... otherwise even always < odd.
}
};

Alternatively, you can use the predicate you have now for sorting, but
do not use a container that requires value uniqueness. For example,
use a vector with your current predicate:

std::vector<int v;
v.push_back(10) ;
v.push_back(7);
v.push_back(5);
v.push_back(18) ;
v.push_back(3);
std::sort(v.beg in(), v.end(), EvenOddSorting( ));

Doing that with EvenOddSorting will place all the even numbers before
all the odd ones. Doing it with EvenOddValueSor ting will sort by
numeric value also. Note that std::sort is not stable; but you can use
std::stable_sor t if that is a requirement. See:

http://www.sgi.com/tech/stl/table_of_contents.html
Thank you, Jason, for your insights and suggestions. I also appreciated
how simpler your predicate looks compared to mine. Before seeing your

bool operator()(cons t int i, const int j) const {
if (i % 2 == 0 && j % 2 == 0 || i % 2 != 0 && j % 2 != 0) {
return i < j;
} else {
return i % 2 == 0;
}
}

But your version seems a bit easier to follow.

Regards,

--
Ney André de Mello Zunino
Jun 27 '08 #5
Ney André de Mello Zunino wrote:
Victor Bazarov wrote:
>What if they are both odd? What if they are both even? Does the
predicate satisfy the requirement of strict weak ordering?

The predicate returns 'true' if the first is even and the second is
odd. For the rest it would return 'false', right? That means that
when comparing 5 and 7 it would determine that 5 is not less than 7.
And when comparing 7 and 5 it would determine that 7 is not less than
5. That seems to me that 5 is the same as 7. That is, 5 and 7 cannot
coexist in the set that has your 'EvenOddSorting ' as the predicate.

Do the same with two evens.

Yes, I see what you mean and it makes perfect sense now.

[...]
>OK, that's what it *should* read (you believe). What *does* it read?

Sorry for not posting the results. You were right, only 10 and 7 were
being accepted in the collection.
>>Notice how my proposed output implies a hidden requirement of
ordering among even and odd numbers. That would be ideal, but I'd be
satisfied (at first) with an output like '18 10 5 7 3'. Would anybody
care to give me a hand?

Not sure what kind of help you are seeking. You've not specified all
the requirements for your predicate to implement it correctly. Have I
given you enough hints to go on?

Yes, sir, you have. Here's the modified functor class (which can
probably be further simplified):

class EvenOddSorting {
public:
bool operator()(cons t int i, const int j) const {
if (i % 2 == 0) {
if (j % 2 != 0) { // i is even and j is odd
return true;
} else { // both i and j are even
return i < j;
}
} else {
if (j % 2 == 0) { // i is odd and j is even
return false;
} else { // both i and j are odd
return i < j;
}
}
}
};

The program now outputs my desired results:

Even-Odd ordered set: 10 18 3 5 7

Do you see any remaining issue?
Issue? Not really. I think you got it now. You can simplify the
predicate a bit by doing

if (i % 2 == j % 2)
return i < j; // for the same oddness - just compare them
else
return i % 2 == 0; // for different, 'i' is smaller if it's even

How's that?

V
--
Jun 27 '08 #6
Ney André de Mello Zunino wrote:
Hello.

It seems a year is all it takes for one's proficiency in C++ to become
too rusty. Professionally, I've been away from the language (and from
programming in general), but I still preserve an appreciation for it.

So I decided to toy with some idea, just for fun and for evaluating how
rusty I'd become. "Let me write a simple functor for sorting the
elements of a collection! I will start with a simple collection of
integers.", I thought. I then chose an unusual criterion for the
sorting: "I'd like the elements to be ordered so that the even members
should appear before the odd ones." The following is what I came up
with. The program is not producing the expected behavior and I suspect
it has to do with my predicate. It is probably not fully complying to
the requirements for such a function.

#include <iostream>
#include <set>
#include <functional>
#include <algorithm>
#include <iterator>

class EvenOddSorting {
public:
bool operator()(cons t int i, const int j) const {
return i % 2 == 0 && j % 2 != 0;
}
};

int main() {
std::set<int, EvenOddSortingi ntSet;
intSet.insert(1 0);
intSet.insert(7 );
intSet.insert(5 );
intSet.insert(1 8);
intSet.insert(3 );
std::cout << "Even-Odd ordered set: ";
std::copy(intSe t.begin(),
intSet.end(),
std::ostream_it erator<int>(std ::cout, " "));
std::cout << "\n";
}

Given the above program, the expected output should read:

Even-Odd ordered set: 10 18 3 5 7

Notice how my proposed output implies a hidden requirement of ordering
among even and odd numbers. That would be ideal, but I'd be satisfied
(at first) with an output like '18 10 5 7 3'. Would anybody care to give
me a hand?

Thank you!
Along with the other advice you got, I've re-written parts of your
original to make it what I consider cleaner.

#include <iostream>
#include <set>
#include <algorithm>
#include <iterator>

class EvenOddSorting {
private:
inline bool isEven(const int i) const {
return 0 == i % 2;
}
public:
inline bool operator()(cons t int i, const int j) const {
return isEven(i+j) ? i < j : isEven(i);
}
};

int main() {
std::set<int, EvenOddSortingi ntSet;
const int values[] = {10, 7, 5, 18, 3};
std::copy(value s,
values + 5,
std::inserter(i ntSet, intSet.begin()) );
std::cout << "Even-Odd ordered set: ";
std::copy(intSe t.begin(),
intSet.end(),
std::ostream_it erator<int>(std ::cout, " "));
std::cout << "\n";
return 0;
}

--
Daniel Pitts' Tech Blog: <http://virtualinfinity .net/wordpress/>
--
Daniel Pitts' Tech Blog: <http://virtualinfinity .net/wordpress/>
Jun 27 '08 #7
In article <g1**********@a ioe.org>, zu****@inf.ufsc .br says...

[ ... ]
class EvenOddSorting {
public:
bool operator()(cons t int i, const int j) const {
return i % 2 == 0 && j % 2 != 0;
}
Just FWIW, the least significant bit of a number is 1 if the number is
odd, and 0 if the number is even. As such, 'i&1' will be 1 iff i is odd.
IOW, the even/odd ordering can be written as: (i&1) < (j&1).

As has already been mentioned, for a set you also need to provide
ordering within the odd and even numbers, so you'll need to add a normal
comparison iff the LSBs are equal.

class EvenOddSorting {
// feel free to return 'i%2' if you prefer
int lsb(int i) const { return i&1; }
public:
bool operator()(int i, int j) const {
return (lsb(i) < lsb(j)) || (lsb(i) == lsb(j) && i<j);
//
// A couple of alterative possibilities that may be more understanable
// to those who don't like boolean expressions.
//
// if (lsb(i) < lsb(j))
// return true;
// return lsb(i)==lsb(j) && i<j;
//
// Possibly even more explicit alternative:
//
// if (lsb(i) < lsb(j))
// return true;
// if (lsb(j) < lsb(i))
// return false;
// return i < j;
}
};

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 27 '08 #8
Some people in this thread have suggested comparison operators that
rely on the result of (i%2) being either 0 or 1, but this may be false
in case the number is negative. Many compilers implement the division
operators so that the quotient is rounded towards zero, which imply
that i%2==-1 when i<0.

Indeed, the following comparison operators have implementation-defined
behaviour (and give a wrong result on my machine when the numbers are
{10, -7, -5, 18, 3} ):

Victor Bazarov's:
class EvenOddSorting {
public:
bool operator()(int i, int j) const {
if (i % 2 == j % 2)
return i < j; // for the same oddness - just compare them
else
return i % 2 == 0; // for different, 'i' is smaller if it's even
}
};
and an alternative suggested by Jerry Coffin:
class EvenOddSorting {
* * * * // feel free to return 'i%2' if you prefer
* * * * int lsb(int i) const { return i%2; }
public:
* * * * bool operator()(int i, int j) const {
* * * * * * * * return (lsb(i) < lsb(j)) || (lsb(i) ==lsb(j) && i<j);
};
Cheers,

Dario
Jun 27 '08 #9
Stefan Ram a écrit :
Vincent Jacques <ne*******@vinc ent-jacques.netwrit es:
>If your compiler generates the same assembly, I do think that
i % 2 is more readable than i & 1, because the 'modulo 2' is
the mathematic operation for 'odd or even'.

I do not see how the readability of »i % 2« depends on the
code my compiler generates.
Sorry for not being clear:

I meant:
(1) there are two cases: (a) the generated code is the same or (b) it is
different.
(2) In general, I think that i % 2 is more readable than i & 1 when you
mean 'odd or even'
(3) I prefer to write readable code over micro-optimized code.

Then I go on the two cases of (1):
case (a): from (2), I write i % 2
case (b): from (3) and (2), I write i % 2 until I'm told (by my
customer, by my hierarchy, etc.) that I *have* to write micro-optimized
code.
»%« is /not/ the mathematical operation »modulo«.
[snip the exact meaning of %]
You're right. Yet, the reminder of the division of i by 2 carries more
about 'odd or even' than the bitwise and between i and 1. (motivation
for (2))
>If your compiler does not generate the same code, then you will have to
profile your code to choose between the two possible solutions.

I do not have to profile, because I usually do not write C++
source code for a specific compiler and execution environment,
I usually do not invest time in such non-portable
microoptimizati ons.
So do I, usually. But, from (2), I assume that the comment from Jerry
Coffin is motivated by an hypothetical win of performance. That's why I

Cheers,
--
Vincent Jacques

"S'il n'y a pas de solution, c'est qu'il n'y a pas de problème"