diff --git a/lib/stdlib/qsort.c b/lib/stdlib/qsort.c index a4a3e431..cc42144b 100644 --- a/lib/stdlib/qsort.c +++ b/lib/stdlib/qsort.c @@ -1,7 +1,6 @@ /* -*-comment-start: "//";comment-end:""-*- * GNU Mes --- Maxwell Equations of Software * Copyright © 2017,2018 Jan (janneke) Nieuwenhuizen - * Copyright © 2021 Paul Dersey * * This file is part of GNU Mes. * @@ -22,47 +21,78 @@ #include void -qswap (void* a, void* b, int size) +qswap (void *a, void *b, size_t size) { - char buffer[size]; - memcpy (buffer, a, size); - memcpy (a, b, size); - memcpy (b, buffer, size); + char *pa = a; + char *pb = b; + do + { + char tmp = *pa; + *pa++ = *pb; + *pb++ = tmp; + } while (--size > 0); +} + +size_t +qpart (void *base, size_t low, size_t high, size_t size, + int (*compare) (void const *, void const *)) +{ + char *pbase = base; + // select the rightmost element as pivot + void *pivot = pbase + high * size; + + // pointer for greater element + size_t i = (low - 1); + + // traverse each element of the array + // compare them with the pivot + for (int j = low; j < high; j++) + { + int c = compare (pbase + j * size, pivot); + if (c < 0) + { + // if element smaller than pivot is found + // swap it with the greater element pointed by i + i++; + + // swap element at i with element at j + void *p1 = pbase + i * size; + void *p2 = pbase + j * size; + qswap (p1, p2, size); + } + } + + // swap the pivot element with the greater element at i + void *p1 = pbase + (i + 1) * size; + void *p2 = pbase + high * size; + qswap (p1, p2, size); + + // return the qpart point + return (i + 1); } void -_qsort (void *base, size_t size, size_t left, size_t right, - int (*compare)(void const*, void const*)) +_qsort (void *base, size_t low, size_t high, size_t size, + int (*compare) (void const *, void const *)) { - char *pbase = base; - int mid = (left + right) / 2; - if (left >= right) + if (low >= high) return; - void *vl = pbase + (left * size); - void *vr = pbase + (mid * size); - qswap (vl, vr, size); + // find the pivot element such that + // elements smaller than pivot are on left of pivot + // elements greater than pivot are on right of pivot + int pi = qpart (base, low, high, size, compare); - int last = left; - for (int i = left + 1; i <= right; i++) - { - void *vt = pbase + (i * size); - if ((*compare)(vl, vt) > 0) - { - ++last; - void *v3 = pbase + (last * size); - qswap (vt, v3, size); - } - } - void *v3 = pbase + (last * size); - qswap (vl, v3, size); - _qsort (base, size, left, last - 1, compare); - _qsort (base, size, last + 1, right, compare); + // recursive call on the left of pivot + _qsort (base, low, pi - 1, size, compare); + + // recursive call on the right of pivot + _qsort (base, pi + 1, high, size, compare); } void qsort (void *base, size_t count, size_t size, - int (*compare)(void const*, void const*)) + int (*compare) (void const *, void const *)) { - _qsort (base, size, 0, count, compare); + _qsort (base, 0, count, size, compare); }