summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-05-01 16:42:10 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-05-01 16:42:10 -0700
commit558363cceda60c12b8fd22cda399e2e39dc11bac (patch)
tree75b1f4d714d2e0ef0d4c13cd4dba32a2fa91cb98 /lib.c
parentcb9b5f6e8ffbec96b5c22ab89bc6852f27dd29b8 (diff)
downloadtxr-558363cceda60c12b8fd22cda399e2e39dc11bac.tar.gz
txr-558363cceda60c12b8fd22cda399e2e39dc11bac.tar.bz2
txr-558363cceda60c12b8fd22cda399e2e39dc11bac.zip
sort: replace Lomuto partitioning with Hoare
I'm seeing numbers aobut the same performance on a sorted vector of integers, and 21% faster on vector of N random integers in the range [0, N). Also, this original algorithm handles well the case of an array consisting of a repeated value. The code we are replacing degrates to quadratic time. * lib.c (med_of_three, middle_pivot): We don't use the return value, so don't calculate and return one. (quicksort): Revise to Hoare: scanning from both ends of the array, exchanging elements. * tests/010/sort.tl: New file. We test sort with lists and vectors from length zero to eight, all permutations.
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c65
1 files changed, 35 insertions, 30 deletions
diff --git a/lib.c b/lib.c
index 417109dd..fdc2d382 100644
--- a/lib.c
+++ b/lib.c
@@ -10791,7 +10791,7 @@ static void swap(val vec, val i, val j)
}
}
-static cnum med_of_three(val vec, val lessfun, val keyfun, cnum from, cnum to,
+static void med_of_three(val vec, val lessfun, val keyfun, cnum from, cnum to,
val *pkval)
{
cnum mid = from + (to - from) / 2;
@@ -10803,62 +10803,67 @@ static cnum med_of_three(val vec, val lessfun, val keyfun, cnum from, cnum to,
val tkval = funcall1(keyfun, tval);
if (funcall2(lessfun, fkval, mkval)) {
- if (funcall2(lessfun, mkval, tval)) {
+ if (funcall2(lessfun, mkval, tval))
*pkval = mkval;
- return mid;
- } else if (funcall2(lessfun, fkval, tkval)) {
+ else if (funcall2(lessfun, fkval, tkval))
*pkval = tkval;
- return to - 1;
- } else {
+ else
*pkval = fkval;
- return from;
- }
} else {
- if (funcall2(lessfun, fkval, tval)) {
+ if (funcall2(lessfun, fkval, tval))
*pkval = fkval;
- return from;
- } else if (funcall2(lessfun, mkval, tkval)) {
+ else if (funcall2(lessfun, mkval, tkval))
*pkval = tkval;
- return to - 1;
- } else {
+ else
*pkval = mkval;
- return mid;
- }
}
}
-static cnum middle_pivot(val vec, val keyfun, cnum from, cnum to,
+static void middle_pivot(val vec, val keyfun, cnum from, cnum to,
val *pkval)
{
cnum pivot = from + (to - from) / 2;
val pval = ref(vec, num_fast(pivot));
*pkval = funcall1(keyfun, pval);
- return pivot;
}
static void quicksort(val vec, val lessfun, val keyfun, cnum from, cnum to)
{
while (to - from >= 2) {
+ cnum i = from - 1;
+ cnum j = to;
val pkval;
- cnum i, j;
- cnum pivot = if3(to - from > 15,
- med_of_three(vec, lessfun, keyfun, from, to, &pkval),
- middle_pivot(vec, keyfun, from, to, &pkval));
- swap(vec, num_fast(pivot), num_fast(to - 1));
+ if (to - from > 15)
+ med_of_three(vec, lessfun, keyfun, from, to, &pkval);
+ else
+ middle_pivot(vec, keyfun, from, to, &pkval);
+
+ for (;;) {
+ do {
+ i++;
+ } while (funcall2(lessfun,
+ funcall1(keyfun, ref(vec, num_fast(i))),
+ pkval));
- for (j = from, i = from; i < to - 1; i++)
- if (funcall2(lessfun, funcall1(keyfun, ref(vec, num_fast(i))), pkval))
- swap(vec, num_fast(i), num_fast(j++));
+ do {
+ j--;
+ } while (i < j && funcall2(lessfun,
+ pkval,
+ funcall1(keyfun, ref(vec, num_fast(j)))));
- swap(vec, num_fast(j), num_fast(to - 1));
+ if (i >= j)
+ break;
+
+ swap(vec, num_fast(i), num_fast(j));
+ }
if (j - from > to - j) {
- quicksort(vec, lessfun, keyfun, j + 1, to);
- to = j;
+ quicksort(vec, lessfun, keyfun, i, to);
+ to = i;
} else {
- quicksort(vec, lessfun, keyfun, from, j);
- from = j + 1;
+ quicksort(vec, lessfun, keyfun, from, i);
+ from = i;
}
}
}