]> git.kaiwu.me - klib.git/commitdiff
added radix sort
authorAttractive Chaos <attractor@live.co.uk>
Fri, 26 Mar 2021 02:08:19 +0000 (22:08 -0400)
committerAttractive Chaos <attractor@live.co.uk>
Fri, 26 Mar 2021 02:08:19 +0000 (22:08 -0400)
ksort.h

diff --git a/ksort.h b/ksort.h
index 4da7a13ef043db7d85a39f5623e131f639de3008..5a2a1a6af5791909fdcca9a2e8d740cb8e1720cc 100644 (file)
--- a/ksort.h
+++ b/ksort.h
@@ -295,4 +295,59 @@ typedef const char *ksstr_t;
 #define KSORT_INIT_GENERIC(type_t) KSORT_INIT(type_t, type_t, ks_lt_generic)
 #define KSORT_INIT_STR KSORT_INIT(str, ksstr_t, ks_lt_str)
 
+#define RS_MIN_SIZE 64
+#define RS_MAX_BITS 8
+
+#define KRADIX_SORT_INIT(name, rstype_t, rskey, sizeof_key) \
+       typedef struct { \
+               rstype_t *b, *e; \
+       } rsbucket_##name##_t; \
+       void rs_insertsort_##name(rstype_t *beg, rstype_t *end) \
+       { \
+               rstype_t *i; \
+               for (i = beg + 1; i < end; ++i) \
+                       if (rskey(*i) < rskey(*(i - 1))) { \
+                               rstype_t *j, tmp = *i; \
+                               for (j = i; j > beg && rskey(tmp) < rskey(*(j-1)); --j) \
+                                       *j = *(j - 1); \
+                               *j = tmp; \
+                       } \
+       } \
+       void rs_sort_##name(rstype_t *beg, rstype_t *end, int n_bits, int s) \
+       { \
+               rstype_t *i; \
+               int size = 1<<n_bits, m = size - 1; \
+               rsbucket_##name##_t *k, b[1<<RS_MAX_BITS], *be = b + size; \
+               assert(n_bits <= RS_MAX_BITS); \
+               for (k = b; k != be; ++k) k->b = k->e = beg; \
+               for (i = beg; i != end; ++i) ++b[rskey(*i)>>s&m].e; \
+               for (k = b + 1; k != be; ++k) \
+                       k->e += (k-1)->e - beg, k->b = (k-1)->e; \
+               for (k = b; k != be;) { \
+                       if (k->b != k->e) { \
+                               rsbucket_##name##_t *l; \
+                               if ((l = b + (rskey(*k->b)>>s&m)) != k) { \
+                                       rstype_t tmp = *k->b, swap; \
+                                       do { \
+                                               swap = tmp; tmp = *l->b; *l->b++ = swap; \
+                                               l = b + (rskey(tmp)>>s&m); \
+                                       } while (l != k); \
+                                       *k->b++ = tmp; \
+                               } else ++k->b; \
+                       } else ++k; \
+               } \
+               for (b->b = beg, k = b + 1; k != be; ++k) k->b = (k-1)->e; \
+               if (s) { \
+                       s = s > n_bits? s - n_bits : 0; \
+                       for (k = b; k != be; ++k) \
+                               if (k->e - k->b > RS_MIN_SIZE) rs_sort_##name(k->b, k->e, n_bits, s); \
+                               else if (k->e - k->b > 1) rs_insertsort_##name(k->b, k->e); \
+               } \
+       } \
+       void radix_sort_##name(rstype_t *beg, rstype_t *end) \
+       { \
+               if (end - beg <= RS_MIN_SIZE) rs_insertsort_##name(beg, end); \
+               else rs_sort_##name(beg, end, RS_MAX_BITS, (sizeof_key - 1) * RS_MAX_BITS); \
+       }
+
 #endif