Home | History | Annotate | Line # | Download | only in stdlib
      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