Skip to content

Instantly share code, notes, and snippets.

@ian-abbott
Last active September 9, 2025 14:00
Show Gist options
  • Select an option

  • Save ian-abbott/7ab29fbb4fe7eaae8776eb58fdb2302a to your computer and use it in GitHub Desktop.

Select an option

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
#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);
}
#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
#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;
}
}
#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