1 1.22 christos /* $NetBSD: radixsort.c,v 1.22 2022/03/12 17:31:39 christos Exp $ */ 2 1.6 thorpej 3 1.1 cgd /*- 4 1.4 mycroft * Copyright (c) 1990, 1993 5 1.4 mycroft * The Regents of the University of California. All rights reserved. 6 1.4 mycroft * 7 1.4 mycroft * This code is derived from software contributed to Berkeley by 8 1.4 mycroft * Peter McIlroy and by Dan Bernstein at New York University, 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.15 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.8 christos #include <sys/cdefs.h> 36 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint) 37 1.6 thorpej #if 0 38 1.10 perry static char sccsid[] = "@(#)radixsort.c 8.2 (Berkeley) 4/28/95"; 39 1.6 thorpej #else 40 1.22 christos __RCSID("$NetBSD: radixsort.c,v 1.22 2022/03/12 17:31:39 christos Exp $"); 41 1.6 thorpej #endif 42 1.1 cgd #endif /* LIBC_SCCS and not lint */ 43 1.1 cgd 44 1.4 mycroft /* 45 1.4 mycroft * Radixsort routines. 46 1.4 mycroft * 47 1.4 mycroft * Program r_sort_a() is unstable but uses O(logN) extra memory for a stack. 48 1.4 mycroft * Use radixsort(a, n, trace, endchar) for this case. 49 1.4 mycroft * 50 1.4 mycroft * For stable sorting (using N extra pointers) use sradixsort(), which calls 51 1.4 mycroft * r_sort_b(). 52 1.4 mycroft * 53 1.4 mycroft * For a description of this code, see D. McIlroy, P. McIlroy, K. Bostic, 54 1.4 mycroft * "Engineering Radix Sort". 55 1.4 mycroft */ 56 1.4 mycroft 57 1.9 jtc #include "namespace.h" 58 1.1 cgd #include <sys/types.h> 59 1.12 lukem 60 1.12 lukem #include <assert.h> 61 1.12 lukem #include <errno.h> 62 1.1 cgd #include <stdlib.h> 63 1.9 jtc 64 1.9 jtc #ifdef __weak_alias 65 1.14 mycroft __weak_alias(radixsort,_radixsort) 66 1.14 mycroft __weak_alias(sradixsort,_sradixsort) 67 1.9 jtc #endif 68 1.1 cgd 69 1.4 mycroft typedef struct { 70 1.4 mycroft const u_char **sa; 71 1.4 mycroft int sn, si; 72 1.4 mycroft } stack; 73 1.4 mycroft 74 1.19 dsl static inline void simplesort(const u_char **, int, int, const u_char *, u_int); 75 1.19 dsl static void r_sort_a(const u_char **, int, int, const u_char *, u_int); 76 1.19 dsl static void r_sort_b(const u_char **, 77 1.19 dsl const u_char **, int, int, const u_char *, u_int); 78 1.4 mycroft 79 1.4 mycroft #define THRESHOLD 20 /* Divert to simplesort(). */ 80 1.4 mycroft #define SIZE 512 /* Default stack size. */ 81 1.4 mycroft 82 1.4 mycroft #define SETUP { \ 83 1.4 mycroft if (tab == NULL) { \ 84 1.4 mycroft tr = tr0; \ 85 1.4 mycroft for (c = 0; c < endch; c++) \ 86 1.4 mycroft tr0[c] = c + 1; \ 87 1.4 mycroft tr0[c] = 0; \ 88 1.4 mycroft for (c++; c < 256; c++) \ 89 1.4 mycroft tr0[c] = c; \ 90 1.4 mycroft endch = 0; \ 91 1.4 mycroft } else { \ 92 1.4 mycroft endch = tab[endch]; \ 93 1.4 mycroft tr = tab; \ 94 1.4 mycroft if (endch != 0 && endch != 255) { \ 95 1.4 mycroft errno = EINVAL; \ 96 1.4 mycroft return (-1); \ 97 1.4 mycroft } \ 98 1.4 mycroft } \ 99 1.4 mycroft } 100 1.1 cgd 101 1.4 mycroft int 102 1.19 dsl radixsort(const u_char **a, int n, const u_char *tab, u_int endch) 103 1.4 mycroft { 104 1.4 mycroft const u_char *tr; 105 1.17 lukem u_int c; 106 1.4 mycroft u_char tr0[256]; 107 1.4 mycroft 108 1.12 lukem _DIAGASSERT(a != NULL); 109 1.12 lukem 110 1.4 mycroft SETUP; 111 1.4 mycroft r_sort_a(a, n, 0, tr, endch); 112 1.4 mycroft return (0); 113 1.1 cgd } 114 1.1 cgd 115 1.1 cgd int 116 1.19 dsl sradixsort(const u_char **a, int n, const u_char *tab, u_int endch) 117 1.1 cgd { 118 1.4 mycroft const u_char *tr, **ta; 119 1.17 lukem u_int c; 120 1.4 mycroft u_char tr0[256]; 121 1.4 mycroft 122 1.12 lukem _DIAGASSERT(a != NULL); 123 1.18 dsl if (a == NULL) { 124 1.12 lukem errno = EFAULT; 125 1.12 lukem return (-1); 126 1.12 lukem } 127 1.12 lukem 128 1.4 mycroft SETUP; 129 1.4 mycroft if (n < THRESHOLD) 130 1.4 mycroft simplesort(a, n, 0, tr, endch); 131 1.1 cgd else { 132 1.20 nia ta = NULL; 133 1.22 christos errno = reallocarr(&ta, n, sizeof(*ta)); 134 1.22 christos if (errno) 135 1.22 christos return -1; 136 1.4 mycroft r_sort_b(a, ta, n, 0, tr, endch); 137 1.4 mycroft free(ta); 138 1.1 cgd } 139 1.4 mycroft return (0); 140 1.4 mycroft } 141 1.1 cgd 142 1.4 mycroft #define empty(s) (s >= sp) 143 1.4 mycroft #define pop(a, n, i) a = (--sp)->sa, n = sp->sn, i = sp->si 144 1.4 mycroft #define push(a, n, i) sp->sa = a, sp->sn = n, (sp++)->si = i 145 1.4 mycroft #define swap(a, b, t) t = a, a = b, b = t 146 1.4 mycroft 147 1.4 mycroft /* Unstable, in-place sort. */ 148 1.10 perry static void 149 1.19 dsl r_sort_a(const u_char **a, int n, int i, const u_char *tr, u_int endch) 150 1.4 mycroft { 151 1.17 lukem static u_int count[256], nc, bmin; 152 1.17 lukem u_int c; 153 1.11 perry const u_char **ak, *r; 154 1.4 mycroft stack s[SIZE], *sp, *sp0, *sp1, temp; 155 1.17 lukem u_int *cp, bigc; 156 1.4 mycroft const u_char **an, *t, **aj, **top[256]; 157 1.4 mycroft 158 1.12 lukem _DIAGASSERT(a != NULL); 159 1.12 lukem _DIAGASSERT(tr != NULL); 160 1.12 lukem 161 1.4 mycroft /* Set up stack. */ 162 1.4 mycroft sp = s; 163 1.4 mycroft push(a, n, i); 164 1.4 mycroft while (!empty(s)) { 165 1.4 mycroft pop(a, n, i); 166 1.4 mycroft if (n < THRESHOLD) { 167 1.4 mycroft simplesort(a, n, i, tr, endch); 168 1.4 mycroft continue; 169 1.4 mycroft } 170 1.4 mycroft an = a + n; 171 1.1 cgd 172 1.4 mycroft /* Make character histogram. */ 173 1.4 mycroft if (nc == 0) { 174 1.4 mycroft bmin = 255; /* First occupied bin, excluding eos. */ 175 1.4 mycroft for (ak = a; ak < an;) { 176 1.4 mycroft c = tr[(*ak++)[i]]; 177 1.4 mycroft if (++count[c] == 1 && c != endch) { 178 1.4 mycroft if (c < bmin) 179 1.4 mycroft bmin = c; 180 1.4 mycroft nc++; 181 1.4 mycroft } 182 1.4 mycroft } 183 1.4 mycroft if (sp + nc > s + SIZE) { /* Get more stack. */ 184 1.4 mycroft r_sort_a(a, n, i, tr, endch); 185 1.4 mycroft continue; 186 1.4 mycroft } 187 1.4 mycroft } 188 1.1 cgd 189 1.1 cgd /* 190 1.4 mycroft * Set top[]; push incompletely sorted bins onto stack. 191 1.4 mycroft * top[] = pointers to last out-of-place element in bins. 192 1.4 mycroft * count[] = counts of elements in bins. 193 1.4 mycroft * Before permuting: top[c-1] + count[c] = top[c]; 194 1.4 mycroft * during deal: top[c] counts down to top[c-1]. 195 1.1 cgd */ 196 1.4 mycroft sp0 = sp1 = sp; /* Stack position of biggest bin. */ 197 1.4 mycroft bigc = 2; /* Size of biggest bin. */ 198 1.4 mycroft if (endch == 0) /* Special case: set top[eos]. */ 199 1.4 mycroft top[0] = ak = a + count[0]; 200 1.4 mycroft else { 201 1.4 mycroft ak = a; 202 1.4 mycroft top[255] = an; 203 1.4 mycroft } 204 1.4 mycroft for (cp = count + bmin; nc > 0; cp++) { 205 1.4 mycroft while (*cp == 0) /* Find next non-empty pile. */ 206 1.4 mycroft cp++; 207 1.4 mycroft if (*cp > 1) { 208 1.4 mycroft if (*cp > bigc) { 209 1.4 mycroft bigc = *cp; 210 1.4 mycroft sp1 = sp; 211 1.4 mycroft } 212 1.4 mycroft push(ak, *cp, i+1); 213 1.1 cgd } 214 1.4 mycroft top[cp-count] = ak += *cp; 215 1.4 mycroft nc--; 216 1.1 cgd } 217 1.4 mycroft swap(*sp0, *sp1, temp); /* Play it safe -- biggest bin last. */ 218 1.1 cgd 219 1.1 cgd /* 220 1.4 mycroft * Permute misplacements home. Already home: everything 221 1.4 mycroft * before aj, and in bin[c], items from top[c] on. 222 1.4 mycroft * Inner loop: 223 1.4 mycroft * r = next element to put in place; 224 1.4 mycroft * ak = top[r[i]] = location to put the next element. 225 1.4 mycroft * aj = bottom of 1st disordered bin. 226 1.4 mycroft * Outer loop: 227 1.4 mycroft * Once the 1st disordered bin is done, ie. aj >= ak, 228 1.4 mycroft * aj<-aj + count[c] connects the bins in a linked list; 229 1.4 mycroft * reset count[c]. 230 1.1 cgd */ 231 1.4 mycroft for (aj = a; aj < an; *aj = r, aj += count[c], count[c] = 0) 232 1.4 mycroft for (r = *aj; aj < (ak = --top[c = tr[r[i]]]);) 233 1.4 mycroft swap(*ak, r, t); 234 1.4 mycroft } 235 1.4 mycroft } 236 1.4 mycroft 237 1.4 mycroft /* Stable sort, requiring additional memory. */ 238 1.10 perry static void 239 1.19 dsl r_sort_b(const u_char **a, const u_char **ta, int n, int i, const u_char *tr, 240 1.19 dsl u_int endch) 241 1.4 mycroft { 242 1.17 lukem static u_int count[256], nc, bmin; 243 1.17 lukem u_int c; 244 1.11 perry const u_char **ak, **ai; 245 1.4 mycroft stack s[512], *sp, *sp0, *sp1, temp; 246 1.4 mycroft const u_char **top[256]; 247 1.17 lukem u_int *cp, bigc; 248 1.4 mycroft 249 1.12 lukem _DIAGASSERT(a != NULL); 250 1.12 lukem _DIAGASSERT(ta != NULL); 251 1.12 lukem _DIAGASSERT(tr != NULL); 252 1.12 lukem 253 1.4 mycroft sp = s; 254 1.4 mycroft push(a, n, i); 255 1.4 mycroft while (!empty(s)) { 256 1.4 mycroft pop(a, n, i); 257 1.4 mycroft if (n < THRESHOLD) { 258 1.4 mycroft simplesort(a, n, i, tr, endch); 259 1.4 mycroft continue; 260 1.1 cgd } 261 1.1 cgd 262 1.4 mycroft if (nc == 0) { 263 1.4 mycroft bmin = 255; 264 1.4 mycroft for (ak = a + n; --ak >= a;) { 265 1.4 mycroft c = tr[(*ak)[i]]; 266 1.4 mycroft if (++count[c] == 1 && c != endch) { 267 1.4 mycroft if (c < bmin) 268 1.4 mycroft bmin = c; 269 1.4 mycroft nc++; 270 1.4 mycroft } 271 1.4 mycroft } 272 1.4 mycroft if (sp + nc > s + SIZE) { 273 1.4 mycroft r_sort_b(a, ta, n, i, tr, endch); 274 1.4 mycroft continue; 275 1.4 mycroft } 276 1.4 mycroft } 277 1.1 cgd 278 1.4 mycroft sp0 = sp1 = sp; 279 1.4 mycroft bigc = 2; 280 1.4 mycroft if (endch == 0) { 281 1.4 mycroft top[0] = ak = a + count[0]; 282 1.4 mycroft count[0] = 0; 283 1.4 mycroft } else { 284 1.4 mycroft ak = a; 285 1.4 mycroft top[255] = a + n; 286 1.4 mycroft count[255] = 0; 287 1.1 cgd } 288 1.4 mycroft for (cp = count + bmin; nc > 0; cp++) { 289 1.4 mycroft while (*cp == 0) 290 1.4 mycroft cp++; 291 1.4 mycroft if ((c = *cp) > 1) { 292 1.4 mycroft if (c > bigc) { 293 1.4 mycroft bigc = c; 294 1.4 mycroft sp1 = sp; 295 1.4 mycroft } 296 1.4 mycroft push(ak, c, i+1); 297 1.4 mycroft } 298 1.4 mycroft top[cp-count] = ak += c; 299 1.4 mycroft *cp = 0; /* Reset count[]. */ 300 1.4 mycroft nc--; 301 1.1 cgd } 302 1.4 mycroft swap(*sp0, *sp1, temp); 303 1.4 mycroft 304 1.4 mycroft for (ak = ta + n, ai = a+n; ak > ta;) /* Copy to temp. */ 305 1.4 mycroft *--ak = *--ai; 306 1.4 mycroft for (ak = ta+n; --ak >= ta;) /* Deal to piles. */ 307 1.4 mycroft *--top[tr[(*ak)[i]]] = *ak; 308 1.1 cgd } 309 1.1 cgd } 310 1.19 dsl 311 1.19 dsl /* insertion sort */ 312 1.16 perry static inline void 313 1.19 dsl simplesort(const u_char **a, int n, int b, const u_char *tr, u_int endch) 314 1.1 cgd { 315 1.11 perry u_char ch; 316 1.4 mycroft const u_char **ak, **ai, *s, *t; 317 1.12 lukem 318 1.12 lukem _DIAGASSERT(a != NULL); 319 1.12 lukem _DIAGASSERT(tr != NULL); 320 1.1 cgd 321 1.4 mycroft for (ak = a+1; --n >= 1; ak++) 322 1.4 mycroft for (ai = ak; ai > a; ai--) { 323 1.4 mycroft for (s = ai[0] + b, t = ai[-1] + b; 324 1.4 mycroft (ch = tr[*s]) != endch; s++, t++) 325 1.4 mycroft if (ch != tr[*t]) 326 1.1 cgd break; 327 1.4 mycroft if (ch >= tr[*t]) 328 1.4 mycroft break; 329 1.4 mycroft swap(ai[0], ai[-1], s); 330 1.4 mycroft } 331 1.1 cgd } 332