1989-05-16 13:13:53 +00:00
|
|
|
/*
|
|
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
|
|
*/
|
1994-06-24 14:02:31 +00:00
|
|
|
/* $Id$ */
|
1989-05-16 13:13:53 +00:00
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
#include <stdlib.h>
|
1989-05-16 13:13:53 +00:00
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
static void qsort1(char*, char*, size_t);
|
|
|
|
static int (*qcompar)(const char*, const char*);
|
|
|
|
static void qexchange(char*, char*, size_t);
|
|
|
|
static void q3exchange(char*, char*, char*, size_t);
|
1989-05-16 13:13:53 +00:00
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
void qsort(void* base, size_t nel, size_t width,
|
|
|
|
int (*compar)(const void*, const void*))
|
1989-05-16 13:13:53 +00:00
|
|
|
{
|
1990-08-28 14:03:24 +00:00
|
|
|
/* when nel is 0, the expression '(nel - 1) * width' is wrong */
|
2018-06-21 20:33:47 +00:00
|
|
|
if (!nel)
|
|
|
|
return;
|
|
|
|
qcompar = (int (*)(const char*, const char*))compar;
|
|
|
|
qsort1(base, (char*)base + (nel - 1) * width, width);
|
1989-05-16 13:13:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-06-21 20:33:47 +00:00
|
|
|
qsort1(char* a1, char* a2, register size_t width)
|
1989-05-16 13:13:53 +00:00
|
|
|
{
|
1989-12-18 15:14:14 +00:00
|
|
|
register char *left, *right;
|
|
|
|
register char *lefteq, *righteq;
|
1989-05-16 13:13:53 +00:00
|
|
|
int cmp;
|
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (a2 <= a1)
|
|
|
|
return;
|
1989-05-16 13:13:53 +00:00
|
|
|
left = a1;
|
|
|
|
right = a2;
|
2018-06-21 20:33:47 +00:00
|
|
|
lefteq = righteq = a1 + width * (((a2 - a1) + width) / (2 * width));
|
|
|
|
/*
|
1989-05-16 13:13:53 +00:00
|
|
|
Pick an element in the middle of the array.
|
|
|
|
We will collect the equals around it.
|
|
|
|
"lefteq" and "righteq" indicate the left and right
|
|
|
|
bounds of the equals respectively.
|
|
|
|
Smaller elements end up left of it, larger elements end
|
|
|
|
up right of it.
|
|
|
|
*/
|
2018-06-21 20:33:47 +00:00
|
|
|
again:
|
|
|
|
while (left < lefteq && (cmp = (*qcompar)(left, lefteq)) <= 0)
|
|
|
|
{
|
|
|
|
if (cmp < 0)
|
|
|
|
{
|
1989-05-16 13:13:53 +00:00
|
|
|
/* leave it where it is */
|
|
|
|
left += width;
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
else
|
|
|
|
{
|
1989-05-16 13:13:53 +00:00
|
|
|
/* equal, so exchange with the element to
|
|
|
|
the left of the "equal"-interval.
|
|
|
|
*/
|
|
|
|
lefteq -= width;
|
|
|
|
qexchange(left, lefteq, width);
|
|
|
|
}
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
while (right > righteq)
|
|
|
|
{
|
|
|
|
if ((cmp = (*qcompar)(right, righteq)) < 0)
|
|
|
|
{
|
1989-05-16 13:13:53 +00:00
|
|
|
/* smaller, should go to left part
|
|
|
|
*/
|
2018-06-21 20:33:47 +00:00
|
|
|
if (left < lefteq)
|
|
|
|
{
|
1989-05-16 13:13:53 +00:00
|
|
|
/* yes, we had a larger one at the
|
|
|
|
left, so we can just exchange
|
|
|
|
*/
|
|
|
|
qexchange(left, right, width);
|
|
|
|
left += width;
|
|
|
|
right -= width;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
/* no more room at the left part, so we
|
|
|
|
move the "equal-interval" one place to the
|
|
|
|
right, and the smaller element to the
|
|
|
|
left of it.
|
|
|
|
This is best expressed as a three-way
|
|
|
|
exchange.
|
|
|
|
*/
|
|
|
|
righteq += width;
|
|
|
|
q3exchange(left, righteq, right, width);
|
|
|
|
lefteq += width;
|
|
|
|
left = lefteq;
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
else if (cmp == 0)
|
|
|
|
{
|
1989-05-16 13:13:53 +00:00
|
|
|
/* equal, so exchange with the element to
|
|
|
|
the right of the "equal-interval"
|
|
|
|
*/
|
|
|
|
righteq += width;
|
|
|
|
qexchange(right, righteq, width);
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
else /* just leave it */
|
|
|
|
right -= width;
|
1989-05-16 13:13:53 +00:00
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
if (left < lefteq)
|
|
|
|
{
|
1989-05-16 13:13:53 +00:00
|
|
|
/* larger element to the left, but no more room,
|
|
|
|
so move the "equal-interval" one place to the
|
|
|
|
left, and the larger element to the right
|
|
|
|
of it.
|
|
|
|
*/
|
|
|
|
lefteq -= width;
|
|
|
|
q3exchange(right, lefteq, left, width);
|
|
|
|
righteq -= width;
|
|
|
|
right = righteq;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
/* now sort the "smaller" part */
|
|
|
|
qsort1(a1, lefteq - width, width);
|
|
|
|
/* and now the larger, saving a subroutine call
|
|
|
|
because of the for(;;)
|
|
|
|
*/
|
|
|
|
a1 = righteq + width;
|
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-06-21 20:33:47 +00:00
|
|
|
qexchange(register char* p, register char* q,
|
|
|
|
register size_t n)
|
1989-05-16 13:13:53 +00:00
|
|
|
{
|
|
|
|
register int c;
|
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
while (n-- > 0)
|
|
|
|
{
|
1989-05-16 13:13:53 +00:00
|
|
|
c = *p;
|
|
|
|
*p++ = *q;
|
|
|
|
*q++ = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-06-21 20:33:47 +00:00
|
|
|
q3exchange(register char* p, register char* q, register char* r,
|
|
|
|
register size_t n)
|
1989-05-16 13:13:53 +00:00
|
|
|
{
|
|
|
|
register int c;
|
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
while (n-- > 0)
|
|
|
|
{
|
1989-05-16 13:13:53 +00:00
|
|
|
c = *p;
|
|
|
|
*p++ = *r;
|
|
|
|
*r++ = *q;
|
|
|
|
*q++ = c;
|
|
|
|
}
|
|
|
|
}
|