Skip to content

Commit

Permalink
basic heap impl
Browse files Browse the repository at this point in the history
  • Loading branch information
voidlizard committed May 11, 2015
1 parent 0a54548 commit 5341d0e
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 2 deletions.
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
.PHONY: ctags clean baseline check

TESTSRC=dradix-test.c hash-test.c slist-test.c clos-test.c
TESTSRC=dradix-test.c hash-test.c slist-test.c clos-test.c heap-test.c

SOURCES=slist.c dradix.c hash.c clos.c hash-test.c dradix-test.c slist-test.c clos-test.c test-suite.c
SOURCES := slist.c dradix.c hash.c clos.c maxheap.c
SOURCES += test-suite.c
SOURCES += $(TESTSRC)

SOURCES+=
all: build-tests

build-tests:
Expand Down
157 changes: 157 additions & 0 deletions heap-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "heap.h"

bool u32_leq(void *a, void *b) {
return *(uint32_t*)a <= *(uint32_t*)b;
}

void u32_cpy(void *a, void *b) {
*(uint32_t*)a = *(uint32_t*)b;
}

void test_heap_test_1(void) {

char heap_mem[heap_mem_size(16, sizeof(uint32_t))];
struct heap *h = heap_create( heap_mem
, sizeof(heap_mem)
, sizeof(uint32_t)
, u32_leq
, u32_cpy );

fprintf(stdout, "# heap_size: %ld\n", heap_size(h));
fprintf(stdout, "# heap_empty: %s\n", heap_empty(h) ? "yes" : "no");

uint32_t vs[] = {9,100,7,2,5,200,1,20,8,8,8,150};
size_t i = 0;
for(; i < sizeof(vs)/sizeof(vs[0]); i++ ) {
if( !heap_add(h, &vs[i]) ) {
break;
}
}

fprintf(stdout, "# heap_empty: %s\n", heap_empty(h) ? "yes" : "no");

while( !heap_empty(h) ) {
uint32_t *mp = heap_pop(h);
if( !mp )
break;
fprintf(stdout, "# %d\n", *mp);
}
}

static void __test_head_add_gt(struct heap *h, uint32_t v) {
if( !heap_full(h) ) {
heap_add(h, &v);
} else {
uint32_t *min = heap_get(h);
if( *min < v ) {
heap_pop(h);
heap_add(h, &v);
}
}
}

void test_heap_test_2(void) {

char heap_mem[heap_mem_size(10, sizeof(uint32_t))];
struct heap *h = heap_create( heap_mem
, sizeof(heap_mem)
, sizeof(uint32_t)
, u32_leq
, u32_cpy );

fprintf(stdout, "# heap_size: %ld\n", heap_size(h));

size_t N = 3000;

size_t n = 0;
for(n = N; n; n-- ) {
__test_head_add_gt(h, n);
}

fprintf(stdout, "\n");
while( !heap_empty(h) ) {
uint32_t *mp = heap_pop(h);
if( !mp )
break;
fprintf(stdout, "# %d\n", *mp);
}

for(n = 0; n <= N; n++ ) {
__test_head_add_gt(h, n);
}

fprintf(stdout, "\n");
while( !heap_empty(h) ) {
uint32_t *mp = heap_pop(h);
if( !mp )
break;
fprintf(stdout, "# %d\n", *mp);
}
}

struct cw {
uint16_t cat;
uint32_t weight;
} __attribute__ ((aligned));

static bool __cw_leq(void *a_, void *b_) {
struct cw *a = a_;
struct cw *b = b_;
return a->weight <= b->weight;
}

static void __cw_cpy(void *a, void *b) {
memcpy(a, b, sizeof(struct cw));
}

void test_heap_test_3(void) {

char heap_mem[heap_mem_size(5, sizeof(struct cw))];
struct heap *h = heap_create( heap_mem
, sizeof(heap_mem)
, sizeof(struct cw)
, __cw_leq
, __cw_cpy );

fprintf(stdout, "# heap_size: %ld\n", heap_size(h));

struct cw cats[] = { { 1, 1 }
, { 2, 1 }
, { 1, 2 }
, { 3, 1 }
, { 12, 3 }
, { 5, 1 }
, { 31, 2 }
, { 6, 2 }
, { 7, 1 }
, { 7, 1 }
, { 10, 5 }
};

fprintf(stdout, "\n");

size_t i = 0;
for(; i < sizeof(cats)/sizeof(cats[0]); i++ ) {
fprintf(stdout, "# {%d, %d}\n", cats[i].cat, cats[i].weight);
if( heap_full(h) ) {
struct cw *min = heap_get(h);
if( __cw_leq(min, &cats[i]) ) {
heap_pop(h);
}
}
heap_add(h, &cats[i]);
}

fprintf(stdout, "\n");
while( !heap_empty(h) ) {
struct cw *c = heap_pop(h);
fprintf(stdout, "# {%d, %d}\n", c->cat, c->weight);
}
}
26 changes: 26 additions & 0 deletions heap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef __heap_h
#define __heap_h

#include <stddef.h>
#include <stdbool.h>

struct heap;

// FIXED SIZE BINARY HEAP

struct heap * heap_create( void *mem
, size_t memsize
, size_t item_size
, bool (*item_leq)(void*,void*)
, void (*item_cpy)(void*,void*)
);

size_t heap_mem_size(size_t n, size_t chunk_size);
size_t heap_size(struct heap*);
bool heap_full(struct heap*);
bool heap_empty(struct heap*);
bool heap_add(struct heap *, void *);
void *heap_get(struct heap*);
void *heap_pop(struct heap*);

#endif
147 changes: 147 additions & 0 deletions maxheap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#include <string.h>
#include <stdint.h>
#include "heap.h"

struct heap {
size_t n;
size_t size;
size_t item_size;
bool (*leq)(void*,void*);
void (*cpy)(void*,void*);
char data[0];
};

struct heap *heap_create( void *mem
, size_t memsize
, size_t item_size
, bool (*item_leq)(void*,void*)
, void (*item_cpy)(void*,void*)
) {

const size_t headsz = sizeof(struct heap);
const size_t minsz = 3*item_size + headsz;

if( memsize < minsz ) {
return 0;
}

struct heap *h = mem;
h->n = 0;
h->size = (memsize - headsz) / item_size;
h->item_size = item_size;
h->leq = item_leq;
h->cpy = item_cpy;

return h;
}

static inline size_t L(size_t i) {
return (i*2 + 1);
}

static inline size_t R(size_t i) {
return (i*2 + 2);
}

static inline size_t P(size_t i) {
return (i-1)/2;
}

static inline void* pitem(struct heap *h, size_t i) {
return &h->data[i*h->item_size];
}

static inline void swap(struct heap *h, size_t i, size_t j) {
char tmp[h->item_size];

void *pi = pitem(h, i);
void *pj = pitem(h, j);

h->cpy(tmp, pi);
h->cpy(pi, pj);
h->cpy(pj, tmp);
}

static inline bool leq(struct heap *h, size_t i, size_t j) {
return h->leq(pitem(h,i), pitem(h,j));
}

static void sift_down(struct heap *h, size_t i) {
while( L(i) < h->n ) {
size_t l = L(i);
size_t r = R(i);
size_t j = l;
if( r < h->n && leq(h, r, l) ) {
j = r;
}
if( leq(h, i, j) ) {
break;
}
swap(h, i, j);
i = j;
}
}

static void sift_up(struct heap *h, size_t i) {
for(; i && leq(h, i, P(i)); i = P(i) ) {
swap(h, i, P(i));
}
}

size_t heap_size(struct heap *h) {
return h->size;
}

size_t heap_mem_size(size_t n, size_t chunk_size) {
return (sizeof(struct heap) + n*chunk_size);
}

bool heap_empty(struct heap *h) {
return (0 == h->n);
}

bool heap_full(struct heap* h) {
return h->n == h->size;
}

bool heap_add(struct heap *h, void *v) {
if( h->n >= h->size ) {
return false;
}

size_t i = h->n++;

h->cpy(pitem(h,i), v);
sift_up(h, i);

return true;
}

void *heap_get(struct heap *h) {

if( !h->n ) {
return 0;
}

return pitem(h, 0);
}

void *heap_pop(struct heap *h) {

if( !h->n ) {
return 0;
}

if( h->n == 1 ) {
h->n--;
return pitem(h, 0);
}

size_t l = --h->n;
swap(h, 0, l);
sift_down(h, 0);

return pitem(h, l);
}


32 changes: 32 additions & 0 deletions t/baseline/33-baseline
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
??? hash create succeed
??? hash items added: 14
??? 0 1000
??? 1 1001
??? 2 1002
??? 3 1003
??? 4 1004
??? 5 1005
??? 6 1006
??? 7 1007
??? 8 1008
??? 9 1009
??? 10 1010
??? 11 1011
??? 12 1012
??? 13 1013
extra items added: 10000
extra items removed
??? 0 1000
??? 1 1001
??? 2 1002
??? 3 1003
??? 4 1004
??? 5 1005
??? 6 1006
??? 7 1007
??? 8 1008
??? 9 1009
??? 10 1010
??? 11 1011
??? 12 1012
??? 13 1013
3 changes: 3 additions & 0 deletions t/baseline/34-baseline
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dummy0
dummy2 14!
dummy2 88!
Loading

0 comments on commit 5341d0e

Please sign in to comment.