1 1.4 riastrad /* $NetBSD: heapsort.c,v 1.4 2025/03/02 16:35:40 riastradh Exp $ */ 2 1.1 ad 3 1.1 ad /*- 4 1.1 ad * Copyright (c) 1991, 1993 5 1.1 ad * The Regents of the University of California. All rights reserved. 6 1.1 ad * 7 1.1 ad * This code is derived from software contributed to Berkeley by 8 1.1 ad * Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias. 9 1.1 ad * 10 1.1 ad * Redistribution and use in source and binary forms, with or without 11 1.1 ad * modification, are permitted provided that the following conditions 12 1.1 ad * are met: 13 1.1 ad * 1. Redistributions of source code must retain the above copyright 14 1.1 ad * notice, this list of conditions and the following disclaimer. 15 1.1 ad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 ad * notice, this list of conditions and the following disclaimer in the 17 1.1 ad * documentation and/or other materials provided with the distribution. 18 1.1 ad * 3. Neither the name of the University nor the names of its contributors 19 1.1 ad * may be used to endorse or promote products derived from this software 20 1.1 ad * without specific prior written permission. 21 1.1 ad * 22 1.1 ad * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 ad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 ad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 ad * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 ad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 ad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 ad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 ad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 ad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 ad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 ad * SUCH DAMAGE. 33 1.1 ad */ 34 1.1 ad 35 1.1 ad #if HAVE_NBTOOL_CONFIG_H 36 1.1 ad #include "nbtool_config.h" 37 1.1 ad /* 38 1.1 ad * XXX Undefine the renames of these functions so that we don't 39 1.1 ad * XXX rename the versions found in the host's headers by mistake! 40 1.1 ad */ 41 1.1 ad #undef heapsort 42 1.4 riastrad #undef heapsort_r 43 1.1 ad #endif 44 1.1 ad 45 1.1 ad #include <sys/cdefs.h> 46 1.1 ad #if defined(LIBC_SCCS) && !defined(lint) 47 1.1 ad #if 0 48 1.1 ad static char sccsid[] = "from: @(#)heapsort.c 8.1 (Berkeley) 6/4/93"; 49 1.1 ad #else 50 1.4 riastrad __RCSID("$NetBSD: heapsort.c,v 1.4 2025/03/02 16:35:40 riastradh Exp $"); 51 1.1 ad #endif 52 1.1 ad #endif /* LIBC_SCCS and not lint */ 53 1.1 ad 54 1.2 jnemeth #if defined(_KERNEL) || defined(_STANDALONE) 55 1.1 ad #include <sys/types.h> 56 1.1 ad 57 1.1 ad #include <lib/libkern/libkern.h> 58 1.2 jnemeth #else /* _KERNEL || _STANDALONE */ 59 1.1 ad #include "namespace.h" 60 1.1 ad #include <sys/types.h> 61 1.1 ad 62 1.1 ad #include <assert.h> 63 1.1 ad #include <errno.h> 64 1.1 ad #include <stdlib.h> 65 1.1 ad 66 1.1 ad #if HAVE_NBTOOL_CONFIG_H 67 1.1 ad /* XXX Now, re-apply the renaming that we undid above. */ 68 1.1 ad #define heapsort __nbcompat_heapsort 69 1.4 riastrad #define heapsort_r __nbcompat_heapsort_r 70 1.1 ad #endif 71 1.1 ad 72 1.1 ad #ifdef __weak_alias 73 1.1 ad __weak_alias(heapsort,_heapsort) 74 1.4 riastrad __weak_alias(heapsort_r,_heapsort_r) 75 1.1 ad #endif 76 1.2 jnemeth #endif /* _KERNEL || _STANDALONE */ 77 1.1 ad 78 1.1 ad /* 79 1.1 ad * Swap two areas of size number of bytes. Although qsort(3) permits random 80 1.1 ad * blocks of memory to be sorted, sorting pointers is almost certainly the 81 1.1 ad * common case (and, were it not, could easily be made so). Regardless, it 82 1.1 ad * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer 83 1.1 ad * arithmetic gets lost in the time required for comparison function calls. 84 1.1 ad */ 85 1.1 ad #define SWAP(a, b, count, size, tmp) { \ 86 1.1 ad count = size; \ 87 1.1 ad do { \ 88 1.1 ad tmp = *a; \ 89 1.1 ad *a++ = *b; \ 90 1.1 ad *b++ = tmp; \ 91 1.1 ad } while (--count); \ 92 1.1 ad } 93 1.1 ad 94 1.1 ad /* Copy one block of size size to another. */ 95 1.1 ad #define COPY(a, b, count, size, tmp1, tmp2) { \ 96 1.1 ad count = size; \ 97 1.1 ad tmp1 = a; \ 98 1.1 ad tmp2 = b; \ 99 1.1 ad do { \ 100 1.1 ad *tmp1++ = *tmp2++; \ 101 1.1 ad } while (--count); \ 102 1.1 ad } 103 1.1 ad 104 1.1 ad /* 105 1.1 ad * Build the list into a heap, where a heap is defined such that for 106 1.1 ad * the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N. 107 1.1 ad * 108 1.1 ad * There are two cases. If j == nmemb, select largest of Ki and Kj. If 109 1.1 ad * j < nmemb, select largest of Ki, Kj and Kj+1. 110 1.1 ad */ 111 1.1 ad #define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) { \ 112 1.1 ad for (par_i = initval; (child_i = par_i * 2) <= nmemb; \ 113 1.1 ad par_i = child_i) { \ 114 1.1 ad child = base + child_i * size; \ 115 1.4 riastrad if (child_i < nmemb && \ 116 1.4 riastrad compar(child, child + size, cookie) < 0) { \ 117 1.1 ad child += size; \ 118 1.1 ad ++child_i; \ 119 1.1 ad } \ 120 1.1 ad par = base + par_i * size; \ 121 1.4 riastrad if (compar(child, par, cookie) <= 0) \ 122 1.1 ad break; \ 123 1.1 ad SWAP(par, child, count, size, tmp); \ 124 1.1 ad } \ 125 1.1 ad } 126 1.1 ad 127 1.1 ad /* 128 1.1 ad * Select the top of the heap and 'heapify'. Since by far the most expensive 129 1.1 ad * action is the call to the compar function, a considerable optimization 130 1.1 ad * in the average case can be achieved due to the fact that k, the displaced 131 1.1 ad * element, is usually quite small, so it would be preferable to first 132 1.1 ad * heapify, always maintaining the invariant that the larger child is copied 133 1.1 ad * over its parent's record. 134 1.1 ad * 135 1.1 ad * Then, starting from the *bottom* of the heap, finding k's correct place, 136 1.1 ad * again maintaining the invariant. As a result of the invariant no element 137 1.1 ad * is 'lost' when k is assigned its correct place in the heap. 138 1.1 ad * 139 1.1 ad * The time savings from this optimization are on the order of 15-20% for the 140 1.1 ad * average case. See Knuth, Vol. 3, page 158, problem 18. 141 1.1 ad * 142 1.1 ad * XXX Don't break the #define SELECT line, below. Reiser cpp gets upset. 143 1.1 ad */ 144 1.1 ad #define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) { \ 145 1.1 ad for (par_i = 1; (child_i = par_i * 2) <= nmemb; par_i = child_i) { \ 146 1.1 ad child = base + child_i * size; \ 147 1.4 riastrad if (child_i < nmemb && \ 148 1.4 riastrad compar(child, child + size, cookie) < 0) { \ 149 1.1 ad child += size; \ 150 1.1 ad ++child_i; \ 151 1.1 ad } \ 152 1.1 ad par = base + par_i * size; \ 153 1.1 ad COPY(par, child, count, size, tmp1, tmp2); \ 154 1.1 ad } \ 155 1.1 ad for (;;) { \ 156 1.1 ad child_i = par_i; \ 157 1.1 ad par_i = child_i / 2; \ 158 1.1 ad child = base + child_i * size; \ 159 1.1 ad par = base + par_i * size; \ 160 1.4 riastrad if (child_i == 1 || compar(k, par, cookie) < 0) { \ 161 1.1 ad COPY(child, k, count, size, tmp1, tmp2); \ 162 1.1 ad break; \ 163 1.1 ad } \ 164 1.1 ad COPY(child, par, count, size, tmp1, tmp2); \ 165 1.1 ad } \ 166 1.1 ad } 167 1.1 ad 168 1.1 ad /* 169 1.1 ad * Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average 170 1.1 ad * and worst. While heapsort is faster than the worst case of quicksort, 171 1.1 ad * the BSD quicksort does median selection so that the chance of finding 172 1.1 ad * a data set that will trigger the worst case is nonexistent. Heapsort's 173 1.1 ad * only advantage over quicksort is that it requires little additional memory. 174 1.1 ad */ 175 1.2 jnemeth #if defined(_KERNEL) || defined(_STANDALONE) 176 1.1 ad int 177 1.4 riastrad kheapsort_r(void *vbase, size_t nmemb, size_t size, 178 1.4 riastrad int (*compar)(const void *, const void *, void *), void *cookie, 179 1.4 riastrad void *k) 180 1.1 ad #else 181 1.1 ad int 182 1.4 riastrad heapsort_r(void *vbase, size_t nmemb, size_t size, 183 1.4 riastrad int (*compar)(const void *, const void *, void *), void *cookie) 184 1.1 ad #endif 185 1.1 ad { 186 1.1 ad size_t cnt, i, j, l; 187 1.1 ad char tmp, *tmp1, *tmp2; 188 1.1 ad char *base, *p, *t; 189 1.3 jnemeth #if !defined(_KERNEL) && !defined(_STANDALONE) 190 1.1 ad char *k; 191 1.1 ad #endif 192 1.1 ad 193 1.1 ad _DIAGASSERT(vbase != NULL); 194 1.1 ad _DIAGASSERT(compar != NULL); 195 1.1 ad 196 1.1 ad if (nmemb <= 1) 197 1.1 ad return (0); 198 1.1 ad 199 1.1 ad if (!size) { 200 1.3 jnemeth #if !defined(_KERNEL) && !defined(_STANDALONE) 201 1.1 ad errno = EINVAL; 202 1.1 ad #endif 203 1.1 ad return (-1); 204 1.1 ad } 205 1.1 ad 206 1.3 jnemeth #if !defined(_KERNEL) && !defined(_STANDALONE) 207 1.1 ad if ((k = malloc(size)) == NULL) 208 1.1 ad return (-1); 209 1.1 ad #endif 210 1.1 ad 211 1.1 ad /* 212 1.1 ad * Items are numbered from 1 to nmemb, so offset from size bytes 213 1.1 ad * below the starting address. 214 1.1 ad */ 215 1.1 ad base = (char *)vbase - size; 216 1.1 ad 217 1.1 ad for (l = nmemb / 2 + 1; --l;) 218 1.1 ad CREATE(l, nmemb, i, j, t, p, size, cnt, tmp); 219 1.1 ad 220 1.1 ad /* 221 1.1 ad * For each element of the heap, save the largest element into its 222 1.1 ad * final slot, save the displaced element (k), then recreate the 223 1.1 ad * heap. 224 1.1 ad */ 225 1.1 ad while (nmemb > 1) { 226 1.1 ad COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2); 227 1.1 ad COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2); 228 1.1 ad --nmemb; 229 1.1 ad SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2); 230 1.1 ad } 231 1.3 jnemeth #if !defined(_KERNEL) && !defined(_STANDALONE) 232 1.1 ad free(k); 233 1.1 ad #endif 234 1.1 ad return (0); 235 1.1 ad } 236 1.4 riastrad 237 1.4 riastrad static int 238 1.4 riastrad cmpnocookie(const void *a, const void *b, void *cookie) 239 1.4 riastrad { 240 1.4 riastrad int (*cmp)(const void *, const void *) = cookie; 241 1.4 riastrad 242 1.4 riastrad return cmp(a, b); 243 1.4 riastrad } 244 1.4 riastrad 245 1.4 riastrad int 246 1.4 riastrad #if defined(_KERNEL) || defined(_STANDALONE) 247 1.4 riastrad kheapsort(void *a, size_t n, size_t es, 248 1.4 riastrad int (*cmp)(const void *, const void *), 249 1.4 riastrad void *k) 250 1.4 riastrad #else 251 1.4 riastrad heapsort(void *a, size_t n, size_t es, 252 1.4 riastrad int (*cmp)(const void *, const void *)) 253 1.4 riastrad #endif 254 1.4 riastrad { 255 1.4 riastrad 256 1.4 riastrad #if defined(_KERNEL) || defined(_STANDALONE) 257 1.4 riastrad return kheapsort_r(a, n, es, cmpnocookie, cmp, k); 258 1.4 riastrad #else 259 1.4 riastrad return heapsort_r(a, n, es, cmpnocookie, cmp); 260 1.4 riastrad #endif 261 1.4 riastrad } 262