From 70fb352656cff5ddbb11718d4becbd40ee1afe26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 3 Dec 2013 11:30:09 +0100 Subject: [PATCH] Fix heapsort, add test --- include/ucore/heapsort.h | 17 +++++-- src/heapsort.c | 26 ++++++----- test/test_heapsort.c | 99 ++++++++++++++++++++++++++++++++++++++++ test/test_runner.c | 4 +- 4 files changed, 130 insertions(+), 16 deletions(-) create mode 100644 test/test_heapsort.c diff --git a/include/ucore/heapsort.h b/include/ucore/heapsort.h index c5dbf01..d6c9a57 100644 --- a/include/ucore/heapsort.h +++ b/include/ucore/heapsort.h @@ -8,11 +8,20 @@ extern "C" { #endif ///compare function. Needs only to return < 0 if //the first element is less than the second -typedef int (*uc_hs_cmp)(const void *, const void *); +typedef int (*uc_hs_cmp)(const void *, const void *, void *cookie); +//swap function +typedef void (*uc_hs_swp)(void *, void *); -void -uc_heapsort(void *base, size_t count, size_t width, - uc_hs_cmp cmp); +/** Sort an array. + * @param base start of array + * @param count number of elements in array + * @param width size of each element + * @param cmp compare function + * @param swap swap function + * @param cookie user pointer passed back to compare function + */ +void uc_heapsort(void *base, size_t count, size_t width, + uc_hs_cmp cmp, uc_hs_swp swap, void *cookie); #ifdef __cplusplus } diff --git a/src/heapsort.c b/src/heapsort.c index e291c89..1157da5 100644 --- a/src/heapsort.c +++ b/src/heapsort.c @@ -3,39 +3,43 @@ static void uc_sift(unsigned char *base, size_t start, size_t count, size_t width, - uc_hs_cmp cmp) + uc_hs_cmp cmp, uc_hs_swp swap, void *cookie) { size_t root = start, child; while ((root * 2 + 1) < count) { child = root * 2 + 1; - if (child < (count - 1) - && cmp(&base[child * width], &base[(child + 1) * width]) < 0) - child++; + if (child < (count - 1)) { + int rc = cmp(&base[child * width], &base[(child + 1) * width], cookie); + if (rc < 0) { + child++; + } + } - if (cmp(&base[root * width], &base[child * width]) < 0) { - memcpy(base + root * width, base + child * width, width); + if (cmp(&base[root * width], &base[child * width], cookie) < 0) { + swap(base + root * width, base + child * width); root = child; - } else + } else { return; + } } } void uc_heapsort(void *base_, size_t count, size_t width, - uc_hs_cmp cmp) + uc_hs_cmp cmp, uc_hs_swp swap, void *cookie) { int start = count / 2 - 1, end = count - 1; unsigned char *base = base_; while (start >= 0) { - uc_sift(base, start, count, width, cmp); + uc_sift(base, start, count, width, cmp, swap, cookie); start--; } while (end > 0) { - memcpy(base + end * width, base, width); - uc_sift(base, 0, end, width, cmp); + swap(base + end * width, base); + uc_sift(base, 0, end, width, cmp, swap, cookie); end--; } } diff --git a/test/test_heapsort.c b/test/test_heapsort.c new file mode 100644 index 0000000..520c6aa --- /dev/null +++ b/test/test_heapsort.c @@ -0,0 +1,99 @@ +#include +#include +#include + +struct Stuff { + char text[11]; + int order; +}; + +static void swap_stuff(void *a_, void *b_) +{ + struct Stuff *a = a_; + struct Stuff *b = b_; + struct Stuff tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + +static int cmp_stuff(const void *a_, const void *b_, void *cookie) +{ + const struct Stuff *a = a_; + const struct Stuff *b = b_; + (void)cookie; + if (a->order < b->order) + return -1; + + return 1; +} + +void print_stuff(const struct Stuff *s, size_t len) +{ + size_t i; + for(i = 0; i < len; i++) { + printf("%s:%d\n", s[i].text, s[i].order); + } +} + +START_TEST (test_heapsort_odd) + struct Stuff unordered[] = { + {"2", 2}, + {"1", 1}, + {"4", 4}, + {"5", 5}, + {"3", 3}, + }; + + struct Stuff ordered[] = { + {"1", 1}, + {"2", 2}, + {"3", 3}, + {"4", 4}, + {"5", 5}, + }; + + uc_heapsort(unordered, ARRAY_SIZE(unordered), sizeof(struct Stuff), + cmp_stuff, swap_stuff, NULL); + //print_stuff(unordered, ARRAY_SIZE(unordered)); + fail_if(memcmp(unordered, ordered, sizeof unordered) != 0); +END_TEST + +START_TEST (test_heapsort_even) + struct Stuff unordered[] = { + {"1", 1}, + {"7", 7}, + {"3", 3}, + {"4", 4}, + {"6", 6}, + {"2", 2}, + }; + + struct Stuff ordered[] = { + {"1", 1}, + {"2", 2}, + {"3", 3}, + {"4", 4}, + {"6", 6}, + {"7", 7}, + }; + + uc_heapsort(unordered, ARRAY_SIZE(unordered), sizeof(struct Stuff), + cmp_stuff, swap_stuff, NULL); + print_stuff(unordered, ARRAY_SIZE(unordered)); + fail_if(memcmp(unordered, ordered, sizeof unordered) != 0); +END_TEST + +Suite *heapsort_suite(void) +{ + Suite *s = suite_create("heapsort"); + TCase *tc = tcase_create("heapsort tests"); + tcase_add_test(tc, test_heapsort_odd); + tcase_add_test(tc, test_heapsort_even); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_runner.c b/test/test_runner.c index a797d5f..2b43008 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -27,6 +27,7 @@ extern Suite *sprintb_suite(void); extern Suite *strv_suite(void); extern Suite *ratelimit_suite(void); extern Suite *htable_suite(void); +extern Suite *heapsort_suite(void); static suite_func suites[] = { bitvec_suite, @@ -48,7 +49,8 @@ static suite_func suites[] = { ratelimit_suite, htable_suite, clock_suite, - threadqueue_suite + threadqueue_suite, + heapsort_suite }; int