noop comparator for qsort

T

Trent Buck

The fourth argument is a comparator that returns `an integer less than,
equal to, or greater than zero' depending on the ordering of its
arguments.

If I don't care about the order and simply want qsort() to run as
quickly as possible, how should the comparator be defined?

If qsort were stable, the following would be best:

int
compare (void *x, void *y)
{
return 0;
}

....is this still true for a possibly non-stable qsort()?

-trent
 
G

Gordon Burditt

The fourth argument is a comparator that returns `an integer less than,
equal to, or greater than zero' depending on the ordering of its
arguments.

If I don't care about the order and simply want qsort() to run as
quickly as possible, how should the comparator be defined?

If you want it to run quickly, don't call qsort() at all.
If qsort were stable, the following would be best:

int
compare (void *x, void *y)
{
return 0;
}

...is this still true for a possibly non-stable qsort()?

Wouldn't it be faster to not call qsort() at all in this
situation? You seem to be OK with having it not change anything.

Some versions of qsort() have been proven to misbehave badly
(e.g. smegmentation fault) if the comparison routine does not
provide a good ordering of the elements, requiring among
other things that
compar(a,b) == -compar(b,a)
and
compar(a,a) == 0
and
if compar(a,b) > 0 and compar(b,c) > 0, then compar(a,c) must be > 0

I am not sure whether qsort() walking off the end of the array if
compar() always returns 1 always violates the requirements of ANSI C
or not.

Gordon L. Burditt
 
T

Trent Buck

Quoth Gordon Burditt on or about 2004-11-14:
Wouldn't it be faster to not call qsort() at all in this
situation? You seem to be OK with having it not change anything.

I'm not actually calling qsort directly. I'm calling scandir; I figured
if I mentioned this I would be told `Go away, this is c.l.c, not
c.p.unix' :)
Some versions of qsort() have been proven to misbehave badly

Blast. OT: is there an better function than scandir? I want a function
that takes the path of a directory and returns a list of names of files
it contains. I don't care how the list is ordered (hence the previous
question).

-trent
 
P

pete

Trent said:
Quoth Gordon Burditt on or about 2004-11-14:

I'm not actually calling qsort directly.
I'm calling scandir; I figured
if I mentioned this I would be told `Go away, this is c.l.c, not
c.p.unix' :)

You don't like c.p.unix?
 
T

Trent Buck

Quoth pete on or about 2004-11-14:
You don't like c.p.unix?

No, I've just never been there (or c.unix.p, silly me) -- and the
original question *was* about pure C. I'll toddle over there in a mo',
see what they have to say.

-trent
 
M

Mark McIntyre

If I don't care about the order

Then why call qsort? Baffling remark !!
and simply want qsort() to run as
quickly as possible, how should the comparator be defined?

It has to be defined in such a way as to return an integer less than, equal
to or greater than zero, in order to indicate which of its arguments is to
be sorted first. Otherwise why bother calling it?
If qsort were stable, the following would be best:

(snip example of useless comparator)
This would be great, if you wanted qsort() to do nothing, possibly taking
infinite time to do it, possibly calling abort() after some implementation
defined loop or recurstion limit, possibly emitting the remark "I'm sorry
Dave, I can't do that..."
 
A

Al Bowers

Trent said:
Quoth Gordon Burditt on or about 2004-11-14:



I'm not actually calling qsort directly. I'm calling scandir; I figured
if I mentioned this I would be told `Go away, this is c.l.c, not
c.p.unix' :)




Blast. OT: is there an better function than scandir? I want a function
that takes the path of a directory and returns a list of names of files
it contains. I don't care how the list is ordered (hence the previous
question).

Nothing OT to Standard C would support this.

<OFF-TOPIC>
You might consider function readdir along with opendir and closedir.
See:
http://www.cis.temple.edu/~ingargio/cis307/readings/dired.c
for an example.
</OFF-TOPIC>
 
T

Trent Buck

Quoth Al Bowers on or about 2004-11-14:
Nothing OT to Standard C would support this.
Hm. Off and On both start with `O'.
You might consider function readdir along with opendir and closedir.
Thank you. I have now switched to open/read/closedir.

-trent
 
K

Kurt Watzka

Mark said:
Then why call qsort? Baffling remark !!


It has to be defined in such a way as to return an integer less than,
equal to or greater than zero, in order to indicate which of its arguments
is to be sorted first. Otherwise why bother calling it?


(snip example of useless comparator)
This would be great, if you wanted qsort() to do nothing, possibly taking
infinite time to do it, possibly calling abort() after some implementation
defined loop or recurstion limit, possibly emitting the remark "I'm sorry
Dave, I can't do that..."

An implementation of qsort() that has a problem with a comperator that
always returns 0 might have problems sorting "int a[] = {1, 1, 1};" with a
perfectly reasonable comperator. For a comperator that always returns 1,
I'd agree with you, but I'd expect qsort to be able to sort an array if
all elements compare equal.

Kurt Watzka
 
K

kevin.bagust

The fourth argument is a comparator that returns `an integer less than,
equal to, or greater than zero' depending on the ordering of its
arguments.
If I don't care about the order and simply want qsort() to run as
quickly as possible, how should the comparator be defined?

How about comparing the pointers rather than the items pointed to? So
something like this:

int compare( void *x, void *y )
{
if ( x < y ) {
return -1;
}
else if ( y < x ) {
return 1;
}
else {
return 0;
}
}

Kevin Bagust.
 
K

Kurt Watzka

kevin.bagust said:
How about comparing the pointers rather than the items pointed to? So
something like this:

Bad idea. qsort may change the position of elements even if they are
properly ordered, so comparing the pointer values may well be an
inconsistent comparator.

Always returning 0 need not eliminate the need to swap values for an
implementation of qsort (remember, qsort ist not even required to implement
quick sort) but at least qsort() should be able with an array of identical
elements. qsort() may fail in astounding ways if a < b and b < c does not
imply a < c.

Kurt Watzka
 
K

Keith Thompson

Trent Buck said:
Quoth Gordon Burditt on or about 2004-11-14:

I'm not actually calling qsort directly. I'm calling scandir; I figured
if I mentioned this I would be told `Go away, this is c.l.c, not
c.p.unix' :)

And one of scandir()'s arguments is a comparison function that's
passed to qsort().

The standard says nothing about the performance of qsort(). If you
pass it a comparison function that always returns 0, you'll get an
unspecified order, but there shouldn't be any problem. The only way
to tell whether this will be faster than using a non-trivial
comparison function is to measure it (or to analyze your system's
implementation of qsort() if you happen to have the source); the
results may or may not apply to any other system.

It would be probably useful for scandir to have a way to specify that
the array doesn't need to be sorted. <OT>On some systems, it
does.</OT>
 
P

Peter Nilsson

kevin.bagust said:
How about comparing the pointers rather than the items pointed to? So
something like this:

int compare( void *x, void *y )

int compare(const void *x, const void *y)
{
if ( x < y ) {
return -1;
}
else if ( y < x ) {
return 1;
}
else {
return 0;
}
}

Or...

#define UFO(x,y) (((y) < (x)) - ((x) < (y)))

int compare(const void *x, const void *y)
{
return UFO(x,y);
}

Trouble is, the standard states...

... The implementation may reorder elements of the array between
calls
to the comparison function, but shall not alter the contents of any
individual element.

There is nothing preventing qsort() from moving array elements in a
maner not determined by the comparison function, so long as the final
result meets the sort criteria.

Many sort implementations actually do this.[1]

AFAIK, it is not possible to make qsort() stable without encoding
original position information in the elements themselves, or having
the comparison function use a 'global' object recording pre-existing
positions.


[1]

% type stable.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define NELEM(x) (sizeof (x) / sizeof *(x))

int compare(const void *s, const void *t)
{
const char * const *u = s;
const char * const *v = t;
int cmp = strncmp(*u, *v, 3);
return cmp ? cmp : (u > v) - (u < v);
}

int main(void)
{
size_t i;
const char *array[] = { "aaa0", "aaa1", "aaa2", "aaa3", "aaa4",
"aaa5", "aaa6", "aaa7", "aaa8", "aaa9" };

fputs("before: ", stdout);
for (i = 0; i < NELEM(array); i++)
putchar(array[3]);
putchar('\n');

qsort(array, NELEM(array), sizeof *array, compare);

fputs(" after: ", stdout);
for (i = 0; i < NELEM(array); i++)
putchar(array[3]);
putchar('\n');

return 0;
}

% gcc -ansi -pedantic stable.c

% a.exe
before: 0123456789
after: 5123406789

%
 
P

pete

Peter Nilsson wrote:
AFAIK, it is not possible to make qsort() stable without encoding
original position information in the elements themselves, or having
the comparison function use a 'global' object recording pre-existing
positions.

You can make qsort() stable, by using a stable
sorting algorithm like bubblesort or insertionsort.

void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
{
unsigned char *array, *high, *low;
unsigned char swap, *p1, *p2, *end;

if (nmemb-- > 1) {
array = base;
do {
low = array;
high = array += size;
while (compar(low, high) > 0) {
p1 = low;
p2 = high;
end = p2 + size;
do {
swap = *p1;
*p1++ = *p2;
*p2++ = swap;
} while (p2 != end);
if (low == base) {
break;
}
high = low;
low -= size;
}
} while (--nmemb != 0);
}
}
 
T

Trent Buck

Quoth Keith Thompson on or about 2004-11-14:
The standard says nothing about the performance of qsort(). If you
pass it a comparison function that always returns 0, you'll get an
unspecified order, but there shouldn't be any problem. The only way
to tell whether this will be faster than using a non-trivial
comparison function is to measure it; the
results may or may not apply to any other system.

Thank you, this is what I had suspected. As I mentioned in another
reply, I have switched to using the opendir/readdir/closedir calls,
which are IIRC in POSIX.1.

-trent
 
L

Lawrence Kirby

On Sun, 14 Nov 2004 09:09:12 +0000, Gordon Burditt wrote:

....
yes

Wouldn't it be faster to not call qsort() at all in this
situation? You seem to be OK with having it not change anything.

Some versions of qsort() have been proven to misbehave badly
(e.g. smegmentation fault) if the comparison routine does not
provide a good ordering of the elements, requiring among
other things that
compar(a,b) == -compar(b,a)
and
compar(a,a) == 0
and
if compar(a,b) > 0 and compar(b,c) > 0, then compar(a,c) must be > 0

Always returning 0 creates a valid ordering relationship - all elements
compare equal, which is quite possible in real data.
I am not sure whether qsort() walking off the end of the array if
compar() always returns 1 always violates the requirements of ANSI C or
not.

Always returning 1 is invalid because compar(a,b) == -compar(b,a) is
violated. AFAICS always returning 0 is the only way to create a valid
comparison function without examining at the data.

Lawrence
 
E

Eric Sosman

Gordon said:
[...]
Some versions of qsort() have been proven to misbehave badly
(e.g. smegmentation fault) if the comparison routine does not
provide a good ordering of the elements, requiring among
other things that
compar(a,b) == -compar(b,a)

This is slightly stronger than the actual requirement:
only the signs of the compar() values are relevant, not
their magnitudes. compar(a,b) == 1 && compar(b,a) == -42
would work just fine.
 
A

Arthur J. O'Dwyer

You can make qsort() stable, by using a stable
sorting algorithm like bubblesort or insertionsort.

If you use your own stable-sorting algorithm, you are no longer using
'qsort', the standard library function Peter was talking about. (He was
speaking from the programmer's point of view, not the implementor's.)

-Arthur
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top