149989Sbostic /*- 249989Sbostic * Copyright (c) 1991 The Regents of the University of California. 349989Sbostic * All rights reserved. 449989Sbostic * 5*50466Sbostic * This code is derived from software contributed to Berkeley by 6*50466Sbostic * Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias. 7*50466Sbostic * 849989Sbostic * %sccs.include.redist.c% 949989Sbostic */ 1049989Sbostic 1149989Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*50466Sbostic static char sccsid[] = "@(#)heapsort.c 5.2 (Berkeley) 07/22/91"; 1349989Sbostic #endif /* LIBC_SCCS and not lint */ 1449989Sbostic 1549989Sbostic #include <sys/cdefs.h> 1649989Sbostic #include <sys/types.h> 1749989Sbostic #include <errno.h> 1849989Sbostic #include <stdlib.h> 1949989Sbostic 2049989Sbostic /* 2149989Sbostic * Swap two areas of size number of bytes. Although qsort(3) permits random 2249989Sbostic * blocks of memory to be sorted, sorting pointers is almost certainly the 2349989Sbostic * common case (and, were it not, could easily be made so). Regardless, it 2449989Sbostic * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer 2549989Sbostic * arithmetic gets lost in the time required for comparison function calls. 2649989Sbostic */ 2749989Sbostic #define SWAP(a, b) { \ 2849989Sbostic cnt = size; \ 2949989Sbostic do { \ 3049989Sbostic ch = *a; \ 3149989Sbostic *a++ = *b; \ 3249989Sbostic *b++ = ch; \ 3349989Sbostic } while (--cnt); \ 3449989Sbostic } 3549989Sbostic 3649989Sbostic /* 3749989Sbostic * Build the list into a heap, where a heap is defined such that for 3849989Sbostic * the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N. 3949989Sbostic * 4049989Sbostic * There two cases. If j == nmemb, select largest of Ki and Kj. If 4149989Sbostic * j < nmemb, select largest of Ki, Kj and Kj+1. 4249989Sbostic * 4349989Sbostic * The initial value depends on if we're building the initial heap or 4449989Sbostic * reconstructing it after saving a value. 4549989Sbostic */ 4649989Sbostic #define HEAP(initval) { \ 4749989Sbostic for (i = initval; (j = i * 2) <= nmemb; i = j) { \ 4849989Sbostic p = (char *)bot + j * size; \ 4949989Sbostic if (j < nmemb && compar(p, p + size) < 0) { \ 5049989Sbostic p += size; \ 5149989Sbostic ++j; \ 5249989Sbostic } \ 5349989Sbostic t = (char *)bot + i * size; \ 5449989Sbostic if (compar(p, t) <= 0) \ 5549989Sbostic break; \ 5649989Sbostic SWAP(t, p); \ 5749989Sbostic } \ 5849989Sbostic } 5949989Sbostic 6049989Sbostic /* 6149989Sbostic * Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average 6249989Sbostic * and worst. While heapsort is faster than the worst case of quicksort, 6349989Sbostic * the BSD quicksort does median selection so that the chance of finding 6449989Sbostic * a data set that will trigger the worst case is nonexistent. Heapsort's 6549989Sbostic * only advantage over quicksort is that it requires no additional memory. 6649989Sbostic */ 6749989Sbostic heapsort(bot, nmemb, size, compar) 6849989Sbostic register void *bot; 6949989Sbostic register size_t nmemb, size; 7049989Sbostic int (*compar) __P((const void *, const void *)); 7149989Sbostic { 7249989Sbostic register char *p, *t, ch; 7349989Sbostic register int cnt, i, j, l; 7449989Sbostic 7549989Sbostic if (nmemb <= 1) 7649989Sbostic return (0); 7749989Sbostic if (!size) { 7849989Sbostic errno = EINVAL; 7949989Sbostic return (-1); 8049989Sbostic } 8149989Sbostic /* 8249989Sbostic * Items are numbered from 1 to nmemb, so offset from size bytes 8349989Sbostic * below the starting address. 8449989Sbostic */ 8549989Sbostic bot -= size; 8649989Sbostic 8749989Sbostic for (l = nmemb / 2 + 1; --l;) 8849989Sbostic HEAP(l); 8949989Sbostic 9049989Sbostic /* 9149989Sbostic * For each element of the heap, save the largest element into its 9249989Sbostic * final slot, then recreate the heap. 9349989Sbostic */ 9449989Sbostic while (nmemb > 1) { 9549989Sbostic p = (char *)bot + size; 9649989Sbostic t = (char *)bot + nmemb * size; 9749989Sbostic SWAP(p, t); 9849989Sbostic --nmemb; 9949989Sbostic HEAP(1); 10049989Sbostic } 10149989Sbostic return (0); 10249989Sbostic } 103