[9] | 1 | /*
|
---|
| 2 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 3 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 4 | */
|
---|
| 5 | /* $Header: /cvsup/minix/src/lib/ansi/qsort.c,v 1.1.1.1 2005/04/21 14:56:06 beng Exp $ */
|
---|
| 6 |
|
---|
| 7 | #include <stdlib.h>
|
---|
| 8 |
|
---|
| 9 | static void qsort1(char *, char *, size_t);
|
---|
| 10 | static int (*qcompar)(const char *, const char *);
|
---|
| 11 | static void qexchange(char *, char *, size_t);
|
---|
| 12 | static void q3exchange(char *, char *, char *, size_t);
|
---|
| 13 |
|
---|
| 14 | void
|
---|
| 15 | qsort(void *base, size_t nel, size_t width,
|
---|
| 16 | int (*compar)(const void *, const void *))
|
---|
| 17 | {
|
---|
| 18 | /* when nel is 0, the expression '(nel - 1) * width' is wrong */
|
---|
| 19 | if (!nel) return;
|
---|
| 20 | qcompar = (int (*)(const char *, const char *)) compar;
|
---|
| 21 | qsort1(base, (char *)base + (nel - 1) * width, width);
|
---|
| 22 | }
|
---|
| 23 |
|
---|
| 24 | static void
|
---|
| 25 | qsort1(char *a1, char *a2, register size_t width)
|
---|
| 26 | {
|
---|
| 27 | register char *left, *right;
|
---|
| 28 | register char *lefteq, *righteq;
|
---|
| 29 | int cmp;
|
---|
| 30 |
|
---|
| 31 | for (;;) {
|
---|
| 32 | if (a2 <= a1) return;
|
---|
| 33 | left = a1;
|
---|
| 34 | right = a2;
|
---|
| 35 | lefteq = righteq = a1 + width * (((a2-a1)+width)/(2*width));
|
---|
| 36 | /*
|
---|
| 37 | Pick an element in the middle of the array.
|
---|
| 38 | We will collect the equals around it.
|
---|
| 39 | "lefteq" and "righteq" indicate the left and right
|
---|
| 40 | bounds of the equals respectively.
|
---|
| 41 | Smaller elements end up left of it, larger elements end
|
---|
| 42 | up right of it.
|
---|
| 43 | */
|
---|
| 44 | again:
|
---|
| 45 | while (left < lefteq && (cmp = (*qcompar)(left, lefteq)) <= 0) {
|
---|
| 46 | if (cmp < 0) {
|
---|
| 47 | /* leave it where it is */
|
---|
| 48 | left += width;
|
---|
| 49 | }
|
---|
| 50 | else {
|
---|
| 51 | /* equal, so exchange with the element to
|
---|
| 52 | the left of the "equal"-interval.
|
---|
| 53 | */
|
---|
| 54 | lefteq -= width;
|
---|
| 55 | qexchange(left, lefteq, width);
|
---|
| 56 | }
|
---|
| 57 | }
|
---|
| 58 | while (right > righteq) {
|
---|
| 59 | if ((cmp = (*qcompar)(right, righteq)) < 0) {
|
---|
| 60 | /* smaller, should go to left part
|
---|
| 61 | */
|
---|
| 62 | if (left < lefteq) {
|
---|
| 63 | /* yes, we had a larger one at the
|
---|
| 64 | left, so we can just exchange
|
---|
| 65 | */
|
---|
| 66 | qexchange(left, right, width);
|
---|
| 67 | left += width;
|
---|
| 68 | right -= width;
|
---|
| 69 | goto again;
|
---|
| 70 | }
|
---|
| 71 | /* no more room at the left part, so we
|
---|
| 72 | move the "equal-interval" one place to the
|
---|
| 73 | right, and the smaller element to the
|
---|
| 74 | left of it.
|
---|
| 75 | This is best expressed as a three-way
|
---|
| 76 | exchange.
|
---|
| 77 | */
|
---|
| 78 | righteq += width;
|
---|
| 79 | q3exchange(left, righteq, right, width);
|
---|
| 80 | lefteq += width;
|
---|
| 81 | left = lefteq;
|
---|
| 82 | }
|
---|
| 83 | else if (cmp == 0) {
|
---|
| 84 | /* equal, so exchange with the element to
|
---|
| 85 | the right of the "equal-interval"
|
---|
| 86 | */
|
---|
| 87 | righteq += width;
|
---|
| 88 | qexchange(right, righteq, width);
|
---|
| 89 | }
|
---|
| 90 | else /* just leave it */ right -= width;
|
---|
| 91 | }
|
---|
| 92 | if (left < lefteq) {
|
---|
| 93 | /* larger element to the left, but no more room,
|
---|
| 94 | so move the "equal-interval" one place to the
|
---|
| 95 | left, and the larger element to the right
|
---|
| 96 | of it.
|
---|
| 97 | */
|
---|
| 98 | lefteq -= width;
|
---|
| 99 | q3exchange(right, lefteq, left, width);
|
---|
| 100 | righteq -= width;
|
---|
| 101 | right = righteq;
|
---|
| 102 | goto again;
|
---|
| 103 | }
|
---|
| 104 | /* now sort the "smaller" part */
|
---|
| 105 | qsort1(a1, lefteq - width, width);
|
---|
| 106 | /* and now the larger, saving a subroutine call
|
---|
| 107 | because of the for(;;)
|
---|
| 108 | */
|
---|
| 109 | a1 = righteq + width;
|
---|
| 110 | }
|
---|
| 111 | /*NOTREACHED*/
|
---|
| 112 | }
|
---|
| 113 |
|
---|
| 114 | static void
|
---|
| 115 | qexchange(register char *p, register char *q,
|
---|
| 116 | register size_t n)
|
---|
| 117 | {
|
---|
| 118 | register int c;
|
---|
| 119 |
|
---|
| 120 | while (n-- > 0) {
|
---|
| 121 | c = *p;
|
---|
| 122 | *p++ = *q;
|
---|
| 123 | *q++ = c;
|
---|
| 124 | }
|
---|
| 125 | }
|
---|
| 126 |
|
---|
| 127 | static void
|
---|
| 128 | q3exchange(register char *p, register char *q, register char *r,
|
---|
| 129 | register size_t n)
|
---|
| 130 | {
|
---|
| 131 | register int c;
|
---|
| 132 |
|
---|
| 133 | while (n-- > 0) {
|
---|
| 134 | c = *p;
|
---|
| 135 | *p++ = *r;
|
---|
| 136 | *r++ = *q;
|
---|
| 137 | *q++ = c;
|
---|
| 138 | }
|
---|
| 139 | }
|
---|