diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2023-05-01 16:42:10 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2023-05-01 16:42:10 -0700 |
commit | 558363cceda60c12b8fd22cda399e2e39dc11bac (patch) | |
tree | 75b1f4d714d2e0ef0d4c13cd4dba32a2fa91cb98 /lib.c | |
parent | cb9b5f6e8ffbec96b5c22ab89bc6852f27dd29b8 (diff) | |
download | txr-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.c | 65 |
1 files changed, 35 insertions, 30 deletions
@@ -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; } } } |