Last active
September 9, 2025 14:00
-
-
Save ian-abbott/7ab29fbb4fe7eaae8776eb58fdb2302a to your computer and use it in GitHub Desktop.
heapsort in C with interface like `qsort` and `qsort_r` in the standard library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stddef.h> | |
| #include "heapsort.h" | |
| #include "swapmem.h" | |
| typedef int (*fnp_compar_arg)(const void *, const void *, void *); | |
| typedef int (*fnp_compar)(const void *, const void *); | |
| static void heapify(unsigned char *base, size_t nmemb, size_t size, size_t root, | |
| fnp_compar_arg compar, void *arg, int hasarg) | |
| { | |
| while (nmemb / 2 > root) { | |
| size_t s = root; | |
| size_t c = 2 * root + 1; | |
| unsigned char *broot = base + (root * size); | |
| unsigned char *bs = base + (s * size); | |
| unsigned char *bc = base + (c * size); | |
| int cmp; | |
| cmp = hasarg ? compar(bc, bs, arg) : ((fnp_compar)compar)(bc, bs); | |
| if (cmp > 0) { | |
| s = c; | |
| bs = bc; | |
| } | |
| if (c < nmemb - 1) { | |
| c++; | |
| bc += size; | |
| cmp = hasarg ? compar(bc, bs, arg) : ((fnp_compar)compar)(bc, bs); | |
| if (cmp > 0) { | |
| s = c; | |
| bs = bc; | |
| } | |
| } | |
| if (s == root) { | |
| break; | |
| } | |
| swapmem(bs, broot, size); | |
| root = s; | |
| } | |
| } | |
| static void heapsort_(void *base, size_t nmemb, size_t size, | |
| fnp_compar_arg compar, void *arg, int hasarg) | |
| { | |
| unsigned char *last; | |
| size_t i; | |
| if (nmemb < 2) { | |
| return; | |
| } | |
| i = nmemb / 2; | |
| while (i--) { | |
| heapify(base, nmemb, size, i, compar, arg, hasarg); | |
| } | |
| i = nmemb; | |
| last = (unsigned char *)base + (i * size); | |
| do { | |
| i--; | |
| last -= size; | |
| swapmem(base, last, size); | |
| heapify(base, i, size, 0, compar, arg, hasarg); | |
| } while (i); | |
| } | |
| void heapsort(void *base, size_t nmemb, size_t size, fnp_compar compar) | |
| { | |
| heapsort_(base, nmemb, size, (fnp_compar_arg)compar, NULL, 0); | |
| } | |
| void heapsort_r(void *base, size_t nmemb, size_t size, | |
| fnp_compar_arg compar, void *arg) | |
| { | |
| heapsort_(base, nmemb, size, compar, arg, 1); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef HEAPSORT_H__INCLUDED | |
| #define HEAPSORT_H__INCLUDED | |
| #include <stddef.h> | |
| void heapsort(void *base, size_t nmemb, size_t size, | |
| int (*compar)(const void *, const void *)); | |
| void heapsort_r(void *base, size_t nmemb, size_t size, | |
| int (*compar)(const void *, const void *, void *), void *arg); | |
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "swapmem.h" | |
| void swapmem(void * restrict a, void * restrict b, size_t size) | |
| { | |
| unsigned char *x = a; | |
| unsigned char *y = b; | |
| unsigned char t; | |
| while (size--) { | |
| t = *x; | |
| *x++ = *y; | |
| *y++ = t; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef SWAPMEM_H__INCLUDED | |
| #define SWAPMEM_H__INCLUDED | |
| #include <stddef.h> | |
| void swapmem(void * restrict a, void * restrict b, size_t size); | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment