diff options
| author | Thomas Schmucker <ts@its1.de> | 2022-04-09 09:46:17 +0200 |
|---|---|---|
| committer | Thomas Schmucker <ts@its1.de> | 2022-04-09 09:46:17 +0200 |
| commit | 38f5e364f73967c01f9ed442fe6646e70cb1dde0 (patch) | |
| tree | 274817eb2793584b0e3d856de5504a614f2b4e89 /src | |
| parent | 2863f4f1d2a6a6a8704454824d6c291d2e0d4b5c (diff) | |
| parent | 154874afda4a8df885e51c01f7681f04fb0b8e61 (diff) | |
| download | data-structures-38f5e364f73967c01f9ed442fe6646e70cb1dde0.tar.gz data-structures-38f5e364f73967c01f9ed442fe6646e70cb1dde0.tar.bz2 data-structures-38f5e364f73967c01f9ed442fe6646e70cb1dde0.zip | |
Merge branch 'rework-directory-structure'
Diffstat (limited to 'src')
| -rw-r--r-- | src/allocator.c | 79 | ||||
| -rw-r--r-- | src/allocator.h | 30 | ||||
| -rw-r--r-- | src/arraylist.c | 368 | ||||
| -rw-r--r-- | src/avl.c | 471 | ||||
| -rw-r--r-- | src/deque.c | 485 | ||||
| -rw-r--r-- | src/dlist.c | 504 | ||||
| -rw-r--r-- | src/hashtab.c | 220 | ||||
| -rw-r--r-- | src/heap.c | 291 | ||||
| -rw-r--r-- | src/insertsort.c | 38 | ||||
| -rw-r--r-- | src/list-tail-node.c | 197 | ||||
| -rw-r--r-- | src/list.c | 264 | ||||
| -rw-r--r-- | src/queue.c | 115 | ||||
| -rw-r--r-- | src/quicksort.c | 684 | ||||
| -rw-r--r-- | src/random.h | 47 | ||||
| -rw-r--r-- | src/rb.c | 614 | ||||
| -rw-r--r-- | src/rc4.c | 156 | ||||
| -rw-r--r-- | src/ringbuff.c | 156 | ||||
| -rw-r--r-- | src/shellsort.c | 63 | ||||
| -rw-r--r-- | src/stack.c | 110 | ||||
| -rw-r--r-- | src/stack2.c | 115 | ||||
| -rw-r--r-- | src/tree.c | 806 | ||||
| -rw-r--r-- | src/treeutil.h | 51 | ||||
| -rw-r--r-- | src/util.h | 24 |
23 files changed, 5888 insertions, 0 deletions
diff --git a/src/allocator.c b/src/allocator.c new file mode 100644 index 0000000..98fa69f --- /dev/null +++ b/src/allocator.c | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | #include "allocator.h" | ||
| 2 | |||
| 3 | #include <stdlib.h> /* malloc */ | ||
| 4 | |||
| 5 | /* Interface Code */ | ||
| 6 | static void * | ||
| 7 | default_allocate(struct allocator *allocator, size_t n) | ||
| 8 | { | ||
| 9 | (void) allocator; | ||
| 10 | return malloc(n); | ||
| 11 | } | ||
| 12 | |||
| 13 | static void | ||
| 14 | default_deallocate(struct allocator *allocator, void *ptr) | ||
| 15 | { | ||
| 16 | (void) allocator; | ||
| 17 | free(ptr); | ||
| 18 | } | ||
| 19 | |||
| 20 | struct allocator allocator_default_allocator = { | ||
| 21 | .allocate = &default_allocate, | ||
| 22 | .deallocate = &default_deallocate | ||
| 23 | }; | ||
| 24 | |||
| 25 | /* Libary Code */ | ||
| 26 | #include <string.h> | ||
| 27 | |||
| 28 | void * | ||
| 29 | allocator_malloc(struct allocator *allocator, size_t n) | ||
| 30 | { | ||
| 31 | if ( !allocator ) { | ||
| 32 | allocator = &allocator_default_allocator; | ||
| 33 | } | ||
| 34 | |||
| 35 | return allocator->allocate(allocator, n); | ||
| 36 | } | ||
| 37 | |||
| 38 | void | ||
| 39 | allocator_free(struct allocator *allocator, void *ptr) | ||
| 40 | { | ||
| 41 | if ( !allocator ) { | ||
| 42 | allocator = &allocator_default_allocator; | ||
| 43 | } | ||
| 44 | |||
| 45 | allocator->deallocate(allocator, ptr); | ||
| 46 | } | ||
| 47 | |||
| 48 | char * | ||
| 49 | allocator_strdup(struct allocator *allocator, const char *str) | ||
| 50 | { | ||
| 51 | size_t n; | ||
| 52 | char * dest; | ||
| 53 | |||
| 54 | n = strlen(str) + 1; | ||
| 55 | dest = allocator_malloc(allocator, n); | ||
| 56 | if ( dest ) { | ||
| 57 | memcpy(dest, str, n); | ||
| 58 | } | ||
| 59 | |||
| 60 | return dest; | ||
| 61 | } | ||
| 62 | |||
| 63 | void * | ||
| 64 | allocator_malloc_zero(struct allocator *allocator, size_t n) | ||
| 65 | { | ||
| 66 | void *ptr; | ||
| 67 | |||
| 68 | ptr = allocator_malloc(allocator, n); | ||
| 69 | if ( ptr ) { | ||
| 70 | memset(ptr, 0, n); | ||
| 71 | } | ||
| 72 | |||
| 73 | return ptr; | ||
| 74 | } | ||
| 75 | |||
| 76 | int | ||
| 77 | main() | ||
| 78 | { | ||
| 79 | } | ||
diff --git a/src/allocator.h b/src/allocator.h new file mode 100644 index 0000000..dd9bb16 --- /dev/null +++ b/src/allocator.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <stddef.h> /* size_t */ | ||
| 4 | |||
| 5 | struct allocator { | ||
| 6 | void *(*allocate)(struct allocator *allocator, size_t n); | ||
| 7 | void (*deallocate)(struct allocator *allocator, void *ptr); | ||
| 8 | }; | ||
| 9 | |||
| 10 | extern struct allocator default_allocator; | ||
| 11 | |||
| 12 | /* allocator interface */ | ||
| 13 | void *allocator_malloc(struct allocator *allocator, size_t n); | ||
| 14 | void allocator_free(struct allocator *allocator, void *ptr); | ||
| 15 | |||
| 16 | /* helper functions */ | ||
| 17 | char *allocator_strdup(struct allocator *allocator, const char *str); | ||
| 18 | void *allocator_malloc_zero(struct allocator *allocator, size_t n); | ||
| 19 | |||
| 20 | #define ALLOCATE(n) \ | ||
| 21 | allocator_malloc(&allocator_default_allocator, (n)) | ||
| 22 | |||
| 23 | #define ALLOCATE_ZERO(n) \ | ||
| 24 | allocator_malloc_zero(&allocator_default_allocator, (n)) | ||
| 25 | |||
| 26 | #define FREE(ptr) \ | ||
| 27 | (allocator_free(&allocator_default_allocator, (ptr)), (ptr) = NULL) | ||
| 28 | |||
| 29 | #define NEW(ptr) ((ptr) = ALLOCATE(sizeof *(ptr))) | ||
| 30 | #define NEW0(ptr) ((ptr) = ALLOCATE_ZERO(sizeof *(ptr))) | ||
diff --git a/src/arraylist.c b/src/arraylist.c new file mode 100644 index 0000000..f010d07 --- /dev/null +++ b/src/arraylist.c | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | /* arraylist */ | ||
| 2 | #include <assert.h> | ||
| 3 | #include <stdbool.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <string.h> | ||
| 7 | #include <time.h> | ||
| 8 | |||
| 9 | #include "util.h" | ||
| 10 | |||
| 11 | typedef int T; | ||
| 12 | |||
| 13 | struct ArrayList { | ||
| 14 | T ** array; | ||
| 15 | size_t size; | ||
| 16 | size_t capacity; | ||
| 17 | }; | ||
| 18 | |||
| 19 | static T ** | ||
| 20 | ArrayList_allocateArray(void *ptr, size_t nelem) | ||
| 21 | { | ||
| 22 | T **new_ptr = reallocarray(ptr, nelem, sizeof *new_ptr); | ||
| 23 | |||
| 24 | if ( new_ptr == NULL ) { | ||
| 25 | ERROR("out of memory"); | ||
| 26 | } | ||
| 27 | |||
| 28 | return new_ptr; | ||
| 29 | } | ||
| 30 | |||
| 31 | void | ||
| 32 | ArrayList_init(struct ArrayList *arrayList) | ||
| 33 | { | ||
| 34 | assert(arrayList); | ||
| 35 | |||
| 36 | arrayList->array = NULL; | ||
| 37 | arrayList->size = 0; | ||
| 38 | arrayList->capacity = 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | struct ArrayList * | ||
| 42 | ArrayList_new(void) | ||
| 43 | { | ||
| 44 | struct ArrayList *arrayList = malloc(sizeof *arrayList); | ||
| 45 | if ( arrayList ) { | ||
| 46 | ArrayList_init(arrayList); | ||
| 47 | } | ||
| 48 | return arrayList; | ||
| 49 | } | ||
| 50 | |||
| 51 | void | ||
| 52 | ArrayList_free(struct ArrayList *arrayList) | ||
| 53 | { | ||
| 54 | assert(arrayList); | ||
| 55 | |||
| 56 | free(arrayList->array); | ||
| 57 | ArrayList_init(arrayList); | ||
| 58 | } | ||
| 59 | |||
| 60 | void | ||
| 61 | ArrayList_delete(struct ArrayList *arrayList) | ||
| 62 | { | ||
| 63 | assert(arrayList); | ||
| 64 | |||
| 65 | ArrayList_free(arrayList); | ||
| 66 | free(arrayList); | ||
| 67 | } | ||
| 68 | |||
| 69 | static void | ||
| 70 | ArrayList_growIfNeeded(struct ArrayList *arrayList) | ||
| 71 | { | ||
| 72 | assert(arrayList); | ||
| 73 | |||
| 74 | if ( arrayList->size == arrayList->capacity ) { | ||
| 75 | if ( arrayList->array == NULL ) { // leere Liste | ||
| 76 | assert(arrayList->size == 0); | ||
| 77 | assert(arrayList->capacity == 0); | ||
| 78 | |||
| 79 | static const size_t DEFAULT_CAPACITY = 10; | ||
| 80 | |||
| 81 | arrayList->capacity = DEFAULT_CAPACITY; | ||
| 82 | arrayList->array = ArrayList_allocateArray(NULL, DEFAULT_CAPACITY); | ||
| 83 | } | ||
| 84 | else { | ||
| 85 | size_t new_capacity = (arrayList->capacity * 3) / 2; // *= 1.5 | ||
| 86 | T ** new_arrayList = ArrayList_allocateArray(arrayList->array, new_capacity); | ||
| 87 | |||
| 88 | arrayList->capacity = new_capacity; | ||
| 89 | arrayList->array = new_arrayList; | ||
| 90 | } | ||
| 91 | |||
| 92 | assert(arrayList->array); | ||
| 93 | } | ||
| 94 | |||
| 95 | assert(arrayList->capacity > arrayList->size); | ||
| 96 | } | ||
| 97 | |||
| 98 | void | ||
| 99 | ArrayList_append(struct ArrayList *arrayList, T *ptr) | ||
| 100 | { | ||
| 101 | assert(arrayList); | ||
| 102 | |||
| 103 | ArrayList_growIfNeeded(arrayList); | ||
| 104 | |||
| 105 | arrayList->array[arrayList->size++] = ptr; | ||
| 106 | } | ||
| 107 | |||
| 108 | void | ||
| 109 | ArrayList_insertAt(struct ArrayList *arrayList, size_t idx, T *ptr) | ||
| 110 | { | ||
| 111 | assert(arrayList); | ||
| 112 | assert(idx <= arrayList->size); // allow last position | ||
| 113 | |||
| 114 | ArrayList_growIfNeeded(arrayList); | ||
| 115 | |||
| 116 | memmove(&arrayList->array[idx + 1], | ||
| 117 | &arrayList->array[idx], | ||
| 118 | (arrayList->size - idx) * sizeof arrayList->array[0]); | ||
| 119 | arrayList->array[idx] = ptr; | ||
| 120 | ++arrayList->size; | ||
| 121 | } | ||
| 122 | |||
| 123 | T * | ||
| 124 | ArrayList_getAt(struct ArrayList *arrayList, size_t idx) | ||
| 125 | { | ||
| 126 | assert(arrayList); | ||
| 127 | assert(idx < arrayList->size); | ||
| 128 | |||
| 129 | return arrayList->array[idx]; | ||
| 130 | } | ||
| 131 | |||
| 132 | size_t | ||
| 133 | ArrayList_size(struct ArrayList *arrayList) | ||
| 134 | { | ||
| 135 | assert(arrayList); | ||
| 136 | |||
| 137 | return arrayList->size; | ||
| 138 | } | ||
| 139 | |||
| 140 | bool | ||
| 141 | ArrayList_empty(struct ArrayList *arrayList) | ||
| 142 | { | ||
| 143 | assert(arrayList); | ||
| 144 | |||
| 145 | return arrayList->size == 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | void | ||
| 149 | ArrayList_removeAt(struct ArrayList *arrayList, size_t idx, void clear_func(T *, void *), void *args) | ||
| 150 | { | ||
| 151 | assert(arrayList); | ||
| 152 | assert(idx < arrayList->size); | ||
| 153 | |||
| 154 | if ( clear_func ) { | ||
| 155 | clear_func(arrayList->array[idx], args); | ||
| 156 | } | ||
| 157 | |||
| 158 | #if defined(ARRAYLIST_KEEP_ORDER) | ||
| 159 | memmove(&arrayList->arrayList[idx], | ||
| 160 | &arrayList->arrayList[idx + 1], | ||
| 161 | (arrayList->size - (idx + 1)) * sizeof arrayList->arrayList[0]); | ||
| 162 | #else | ||
| 163 | arrayList->array[idx] = arrayList->array[arrayList->size - 1]; | ||
| 164 | #endif | ||
| 165 | |||
| 166 | --arrayList->size; | ||
| 167 | } | ||
| 168 | |||
| 169 | struct qsortHelper_context { | ||
| 170 | int (*cmp)(const T *, const T *, void *); | ||
| 171 | void *args; | ||
| 172 | }; | ||
| 173 | |||
| 174 | typedef const T *const_T_ptr; | ||
| 175 | |||
| 176 | static int | ||
| 177 | ArrayList_qsortHelper(void *ctx, const void *a, const void *b) | ||
| 178 | { | ||
| 179 | const const_T_ptr *aa = a; | ||
| 180 | const const_T_ptr *bb = b; | ||
| 181 | |||
| 182 | const struct qsortHelper_context *context = ctx; | ||
| 183 | |||
| 184 | return context->cmp(*aa, *bb, context->args); | ||
| 185 | } | ||
| 186 | |||
| 187 | void | ||
| 188 | ArrayList_sort(struct ArrayList *arrayList, int cmp(const T *, const T *, void *), void *args) | ||
| 189 | { | ||
| 190 | assert(arrayList); | ||
| 191 | assert(cmp); | ||
| 192 | |||
| 193 | struct qsortHelper_context context = { | ||
| 194 | .cmp = cmp, | ||
| 195 | .args = args | ||
| 196 | }; | ||
| 197 | |||
| 198 | // Das vollständige qsort_x()-Drama: https://stackoverflow.com/a/46042467 | ||
| 199 | qsort_r(arrayList->array, arrayList->size, sizeof arrayList->array[0], &context, ArrayList_qsortHelper); | ||
| 200 | } | ||
| 201 | |||
| 202 | bool | ||
| 203 | ArrayList_linearSearch(struct ArrayList *arrayList, void *key, int cmp(void *, const T *, void *), void *args, size_t *loc) | ||
| 204 | { | ||
| 205 | assert(arrayList); | ||
| 206 | assert(cmp); | ||
| 207 | assert(loc); | ||
| 208 | |||
| 209 | for ( size_t idx = 0; idx != arrayList->size; ++idx ) { | ||
| 210 | if ( cmp(key, arrayList->array[idx], args) == 0 ) { | ||
| 211 | *loc = idx; | ||
| 212 | return true; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | return false; | ||
| 216 | } | ||
| 217 | |||
| 218 | struct bsearchHelper_context { | ||
| 219 | void *key; | ||
| 220 | int (*cmp)(void *, const T *, void *); | ||
| 221 | void *args; | ||
| 222 | }; | ||
| 223 | |||
| 224 | static int | ||
| 225 | ArrayList_bsearchHelper(const void *ctx, const void *el) | ||
| 226 | { | ||
| 227 | const struct bsearchHelper_context *context = ctx; | ||
| 228 | const const_T_ptr * element = el; | ||
| 229 | |||
| 230 | return context->cmp(context->key, *element, context->args); | ||
| 231 | } | ||
| 232 | |||
| 233 | bool | ||
| 234 | ArrayList_binarySearch(struct ArrayList *arrayList, void *key, int cmp(void *, const T *, void *), void *args, size_t *loc) | ||
| 235 | { | ||
| 236 | assert(arrayList); | ||
| 237 | assert(cmp); | ||
| 238 | assert(loc); | ||
| 239 | |||
| 240 | struct bsearchHelper_context context = { | ||
| 241 | .key = key, | ||
| 242 | .cmp = cmp, | ||
| 243 | .args = args | ||
| 244 | }; | ||
| 245 | |||
| 246 | T **pos = bsearch(&context, arrayList->array, arrayList->size, sizeof arrayList->array[0], ArrayList_bsearchHelper); | ||
| 247 | if ( pos ) { | ||
| 248 | *loc = (size_t)(pos - arrayList->array); | ||
| 249 | return true; | ||
| 250 | } | ||
| 251 | else { | ||
| 252 | return false; | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | void | ||
| 257 | ArrayList_shuffle(struct ArrayList *arrayList, size_t rng(size_t, void *), void *args) | ||
| 258 | { | ||
| 259 | assert(arrayList); | ||
| 260 | assert(rng); | ||
| 261 | |||
| 262 | if ( arrayList->size > 1 ) { | ||
| 263 | for ( size_t i = arrayList->size - 1; i > 0; --i ) { | ||
| 264 | size_t j = rng(i + 1, args); | ||
| 265 | |||
| 266 | // swap | ||
| 267 | T *t = arrayList->array[j]; | ||
| 268 | arrayList->array[j] = arrayList->array[i]; | ||
| 269 | arrayList->array[i] = t; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | static void | ||
| 275 | ArrayList_debugPrint(struct ArrayList *arrayList) | ||
| 276 | { | ||
| 277 | for ( size_t idx = 0; idx != ArrayList_size(arrayList); ++idx ) { | ||
| 278 | T *ptr = ArrayList_getAt(arrayList, idx); | ||
| 279 | printf("%d, ", *ptr); | ||
| 280 | } | ||
| 281 | putchar('\n'); | ||
| 282 | } | ||
| 283 | |||
| 284 | static int | ||
| 285 | my_compare(const T *a, const T *b, void *args) | ||
| 286 | { | ||
| 287 | (void) args; | ||
| 288 | |||
| 289 | if ( *a > *b ) | ||
| 290 | return 1; | ||
| 291 | else if ( *a < *b ) | ||
| 292 | return -1; | ||
| 293 | else | ||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | |||
| 297 | static int | ||
| 298 | my_search_compare(void *key, const T *element, void *args) | ||
| 299 | { | ||
| 300 | (void) args; | ||
| 301 | |||
| 302 | int *a = key; | ||
| 303 | |||
| 304 | if ( *a < *element ) | ||
| 305 | return -1; | ||
| 306 | else if ( *a > *element ) | ||
| 307 | return 1; | ||
| 308 | else | ||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | static size_t | ||
| 313 | my_rng(size_t max, void *args) | ||
| 314 | { | ||
| 315 | (void) args; | ||
| 316 | return (size_t) rand() % max; | ||
| 317 | } | ||
| 318 | |||
| 319 | static void | ||
| 320 | ArrayList_testSort(struct ArrayList *arrayList) | ||
| 321 | { | ||
| 322 | for ( size_t i = 1; i < arrayList->size; ++i ) { | ||
| 323 | if ( *arrayList->array[i - 1] > *arrayList->array[i] ) { | ||
| 324 | fprintf(stderr, "Fehler: %zu (%d, %d)\n", i, *arrayList->array[i - 1], *arrayList->array[i]); | ||
| 325 | exit(EXIT_FAILURE); | ||
| 326 | } | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | int | ||
| 331 | main(void) | ||
| 332 | { | ||
| 333 | srand(time(NULL)); | ||
| 334 | |||
| 335 | int a = 11, b = 22, c = 33, d = 44; | ||
| 336 | |||
| 337 | struct ArrayList *arrayList = ArrayList_new(); | ||
| 338 | |||
| 339 | ArrayList_append(arrayList, &a); | ||
| 340 | ArrayList_append(arrayList, &b); | ||
| 341 | ArrayList_append(arrayList, &c); | ||
| 342 | ArrayList_append(arrayList, &d); | ||
| 343 | ArrayList_debugPrint(arrayList); // 11, 22, 33, 44 | ||
| 344 | |||
| 345 | ArrayList_removeAt(arrayList, 0, NULL, NULL); | ||
| 346 | ArrayList_debugPrint(arrayList); // 44, 22, 33 | ||
| 347 | |||
| 348 | ArrayList_insertAt(arrayList, 3, &a); | ||
| 349 | ArrayList_debugPrint(arrayList); // 44, 22, 33, 11 | ||
| 350 | |||
| 351 | ArrayList_sort(arrayList, my_compare, NULL); | ||
| 352 | ArrayList_testSort(arrayList); | ||
| 353 | |||
| 354 | ArrayList_debugPrint(arrayList); // 11, 22, 33, 44 | ||
| 355 | |||
| 356 | size_t loc; | ||
| 357 | int dummy = 44; | ||
| 358 | if ( ArrayList_binarySearch(arrayList, &dummy, my_search_compare, NULL, &loc) ) { | ||
| 359 | printf("Gefunden: %zu\n", loc); | ||
| 360 | } | ||
| 361 | |||
| 362 | ArrayList_shuffle(arrayList, my_rng, NULL); | ||
| 363 | ArrayList_debugPrint(arrayList); // ?? | ||
| 364 | |||
| 365 | ArrayList_delete(arrayList); | ||
| 366 | |||
| 367 | return EXIT_SUCCESS; | ||
| 368 | } | ||
diff --git a/src/avl.c b/src/avl.c new file mode 100644 index 0000000..874cc6c --- /dev/null +++ b/src/avl.c | |||
| @@ -0,0 +1,471 @@ | |||
| 1 | // AVL Tree | ||
| 2 | #include <assert.h> | ||
| 3 | #include <stdbool.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <time.h> | ||
| 7 | |||
| 8 | /* utils */ | ||
| 9 | #include "util.h" | ||
| 10 | |||
| 11 | // clang-format off | ||
| 12 | |||
| 13 | // Review: http://www.inr.ac.ru/~info21/ADen/ | ||
| 14 | // Tests: https://stackoverflow.com/q/3955680 | ||
| 15 | |||
| 16 | /* --8<-- avl_type */ | ||
| 17 | typedef int T; | ||
| 18 | |||
| 19 | struct tree_node { | ||
| 20 | struct tree_node *left, *right; | ||
| 21 | int bal; | ||
| 22 | T key; | ||
| 23 | int count; /* collision counter */ | ||
| 24 | /* ggf. weitere Felder... */ | ||
| 25 | }; | ||
| 26 | /* -->8-- */ | ||
| 27 | |||
| 28 | /* --8<-- avl_insert_r */ | ||
| 29 | static struct tree_node * | ||
| 30 | insert_r(T x, struct tree_node *p, bool *h) | ||
| 31 | { | ||
| 32 | struct tree_node *p1, *p2; | ||
| 33 | |||
| 34 | if ( p == NULL ) { | ||
| 35 | *h = true; | ||
| 36 | |||
| 37 | p = malloc(sizeof *p); | ||
| 38 | if ( p ) { | ||
| 39 | p->left = NULL; | ||
| 40 | p->right = NULL; | ||
| 41 | p->bal = 0; | ||
| 42 | |||
| 43 | p->key = x; | ||
| 44 | p->count = 1; /* hit counter */ | ||
| 45 | } | ||
| 46 | else | ||
| 47 | ERROR("out of memory"); | ||
| 48 | } | ||
| 49 | else if ( x < p->key ) { | ||
| 50 | p->left = insert_r(x, p->left, h); | ||
| 51 | |||
| 52 | if ( *h ) { | ||
| 53 | if ( p->bal == +1 ) { | ||
| 54 | p->bal = 0; | ||
| 55 | *h = false; | ||
| 56 | } | ||
| 57 | else if ( p->bal == 0 ) { | ||
| 58 | p->bal = -1; | ||
| 59 | } | ||
| 60 | else /* if ( p->bal == -1 ) */ { | ||
| 61 | p1 = p->left; | ||
| 62 | if ( p1->bal == -1 ) { /* single LL rotation */ | ||
| 63 | p->left = p1->right; p1->right = p; | ||
| 64 | p->bal = 0; p = p1; | ||
| 65 | } | ||
| 66 | else { /* double LR rotation */ | ||
| 67 | p2 = p1->right; | ||
| 68 | p1->right = p2->left; p2->left = p1; | ||
| 69 | p->left = p2->right; p2->right = p; | ||
| 70 | p->bal = ( p2->bal == -1 ) ? +1 : 0; | ||
| 71 | p1->bal = ( p2->bal == +1 ) ? -1 : 0; | ||
| 72 | p = p2; | ||
| 73 | } | ||
| 74 | p->bal = 0; | ||
| 75 | *h = false; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | else if ( x > p->key ) { | ||
| 80 | p->right = insert_r(x, p->right, h); | ||
| 81 | |||
| 82 | if ( *h ) { | ||
| 83 | if ( p->bal == -1 ) { | ||
| 84 | p->bal = 0; | ||
| 85 | *h = false; | ||
| 86 | } | ||
| 87 | else if ( p->bal == 0 ) { | ||
| 88 | p->bal = +1; | ||
| 89 | } | ||
| 90 | else /* if ( p->bal == +1 ) */ { | ||
| 91 | p1 = p->right; | ||
| 92 | if ( p1->bal == +1 ) { /* single RR rotation */ | ||
| 93 | p->right = p1->left; p1->left = p; | ||
| 94 | p->bal = 0; p = p1; | ||
| 95 | } | ||
| 96 | else { /* double RL rotation */ | ||
| 97 | p2 = p1->left; | ||
| 98 | p1->left = p2->right; p2->right = p1; | ||
| 99 | p->right = p2->left; p2->left = p; | ||
| 100 | p->bal = ( p2->bal == +1 ) ? -1 : 0; | ||
| 101 | p1->bal = ( p2->bal == -1 ) ? +1 : 0; | ||
| 102 | p = p2; | ||
| 103 | } | ||
| 104 | p->bal = 0; | ||
| 105 | *h = false; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | } | ||
| 109 | else { | ||
| 110 | /* handle collision! */ | ||
| 111 | p->count++; /* hit counter */ | ||
| 112 | *h = false; | ||
| 113 | } | ||
| 114 | assert(p != NULL); | ||
| 115 | |||
| 116 | return p; | ||
| 117 | } | ||
| 118 | /* -->8-- */ | ||
| 119 | |||
| 120 | /* --8<-- avl_insert */ | ||
| 121 | struct tree_node * | ||
| 122 | insert(struct tree_node *tree, T data) | ||
| 123 | { | ||
| 124 | bool h = false; | ||
| 125 | return insert_r(data, tree, &h); | ||
| 126 | } | ||
| 127 | /* -->8-- */ | ||
| 128 | |||
| 129 | /* --8<-- avl_balanceL */ | ||
| 130 | static struct tree_node * | ||
| 131 | balanceL(struct tree_node *p, bool *h) | ||
| 132 | { | ||
| 133 | if ( p->bal == -1 ) { | ||
| 134 | p->bal = 0; | ||
| 135 | } | ||
| 136 | else if ( p->bal == 0 ) { | ||
| 137 | p->bal = +1; | ||
| 138 | *h = false; | ||
| 139 | } | ||
| 140 | else /* if ( p->bal == +1 ) */ { /* rebalance */ | ||
| 141 | struct tree_node *p1 = p->right; | ||
| 142 | if ( p1->bal >= 0 ) { /* singla RR rotation */ | ||
| 143 | p->right = p1->left; | ||
| 144 | p1->left = p; | ||
| 145 | if ( p1->bal == 0 ) { | ||
| 146 | p->bal = +1; | ||
| 147 | p1->bal = -1; | ||
| 148 | *h = false; | ||
| 149 | } | ||
| 150 | else { | ||
| 151 | p->bal = 0; | ||
| 152 | p1->bal = 0; | ||
| 153 | } | ||
| 154 | p = p1; | ||
| 155 | } | ||
| 156 | else { /* double RL rotation */ | ||
| 157 | struct tree_node *p2 = p1->left; | ||
| 158 | p1->left = p2->right; | ||
| 159 | p2->right = p1; | ||
| 160 | p->right = p2->left; | ||
| 161 | p2->left = p; | ||
| 162 | p->bal = ( p2->bal == +1 ) ? -1 : 0; | ||
| 163 | p1->bal = ( p2->bal == -1 ) ? +1 : 0; | ||
| 164 | p = p2; | ||
| 165 | p2->bal = 0; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | return p; | ||
| 169 | } | ||
| 170 | /* -->8-- */ | ||
| 171 | |||
| 172 | /* --8<-- avl_balanceR */ | ||
| 173 | static struct tree_node * | ||
| 174 | balanceR(struct tree_node *p, bool *h) | ||
| 175 | { | ||
| 176 | if ( p->bal == +1 ) { | ||
| 177 | p->bal = 0; | ||
| 178 | } | ||
| 179 | else if ( p->bal == 0 ) { | ||
| 180 | p->bal = -1; | ||
| 181 | *h = false; | ||
| 182 | } | ||
| 183 | else /* p->bal == -1 */ { /* rebalance */ | ||
| 184 | struct tree_node *p1 = p->left; | ||
| 185 | if ( p1->bal <= 0 ) { /* single LL rotation */ | ||
| 186 | p->left = p1->right; | ||
| 187 | p1->right = p; | ||
| 188 | if ( p1->bal == 0 ) { | ||
| 189 | p->bal = -1; | ||
| 190 | p1->bal = +1; | ||
| 191 | *h = false; | ||
| 192 | } | ||
| 193 | else { | ||
| 194 | p->bal = 0; | ||
| 195 | p1->bal = 0; | ||
| 196 | } | ||
| 197 | p = p1; | ||
| 198 | } | ||
| 199 | else { /* double LR rotation */ | ||
| 200 | struct tree_node *p2 = p1->right; | ||
| 201 | p1->right = p2->left; | ||
| 202 | p2->left = p1; | ||
| 203 | p->left = p2->right; | ||
| 204 | p2->right = p; | ||
| 205 | p->bal = ( p2->bal == -1 ) ? +1 : 0; | ||
| 206 | p1->bal = ( p2->bal == +1 ) ? -1 : 0; | ||
| 207 | p = p2; | ||
| 208 | p2->bal = 0; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | return p; | ||
| 212 | } | ||
| 213 | /* -->8-- */ | ||
| 214 | |||
| 215 | /* --8<-- avl_del */ | ||
| 216 | static void | ||
| 217 | del(struct tree_node **q, struct tree_node **r, bool *h) | ||
| 218 | { | ||
| 219 | if ( (*r)->right ) { | ||
| 220 | del(q, &(*r)->right, h); | ||
| 221 | if ( *h ) | ||
| 222 | *r = balanceR(*r, h); | ||
| 223 | } | ||
| 224 | else { | ||
| 225 | /* copy data */ | ||
| 226 | (*q)->key = (*r)->key; | ||
| 227 | (*q)->count = (*r)->count; | ||
| 228 | |||
| 229 | *q = *r; | ||
| 230 | *r = (*r)->left; | ||
| 231 | *h = true; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | /* -->8-- */ | ||
| 235 | |||
| 236 | /* --8<-- avl_delete_r */ | ||
| 237 | static struct tree_node * | ||
| 238 | delete_r(T x, struct tree_node *p, bool *h) | ||
| 239 | { | ||
| 240 | if ( p == NULL ) { | ||
| 241 | ERROR("key not found"); | ||
| 242 | } | ||
| 243 | else if ( x < p->key ) { | ||
| 244 | p->left = delete_r(x, p->left, h); | ||
| 245 | if ( *h ) | ||
| 246 | p = balanceL(p, h); | ||
| 247 | } | ||
| 248 | else if ( x > p->key ) { | ||
| 249 | p->right = delete_r(x, p->right, h); | ||
| 250 | if ( *h ) | ||
| 251 | p = balanceR(p, h); | ||
| 252 | } | ||
| 253 | else /* if ( x == p->key ) */ { | ||
| 254 | struct tree_node *q = p; | ||
| 255 | if ( q->right == NULL ) { | ||
| 256 | p = q->left; | ||
| 257 | *h = true; | ||
| 258 | } | ||
| 259 | else if ( q->left == NULL ) { | ||
| 260 | p = q->right; | ||
| 261 | *h = true; | ||
| 262 | } | ||
| 263 | else { | ||
| 264 | del(&q, &q->left, h); | ||
| 265 | if ( *h ) | ||
| 266 | p = balanceL(p, h); | ||
| 267 | } | ||
| 268 | free(q); | ||
| 269 | } | ||
| 270 | return p; | ||
| 271 | } | ||
| 272 | /* -->8-- */ | ||
| 273 | |||
| 274 | /* --8<-- avl_delete */ | ||
| 275 | struct tree_node * | ||
| 276 | delete(struct tree_node *tree, T data) | ||
| 277 | { | ||
| 278 | bool h = false; | ||
| 279 | return delete_r(data, tree, &h); | ||
| 280 | } | ||
| 281 | /* -->8-- */ | ||
| 282 | |||
| 283 | // aux display and verification routines, helpful but not essential | ||
| 284 | struct trunk { | ||
| 285 | struct trunk *prev; | ||
| 286 | char * str; | ||
| 287 | }; | ||
| 288 | |||
| 289 | void show_trunks(struct trunk *p) | ||
| 290 | { | ||
| 291 | if (!p) return; | ||
| 292 | show_trunks(p->prev); | ||
| 293 | printf("%s", p->str); | ||
| 294 | } | ||
| 295 | |||
| 296 | // this is very haphazzard | ||
| 297 | void show_tree(struct tree_node *root, struct trunk *prev, int is_left) | ||
| 298 | { | ||
| 299 | if (root == NULL) return; | ||
| 300 | |||
| 301 | struct trunk this_disp = { prev, " " }; | ||
| 302 | char *prev_str = this_disp.str; | ||
| 303 | show_tree(root->right, &this_disp, 1); | ||
| 304 | |||
| 305 | if (!prev) | ||
| 306 | this_disp.str = "---"; | ||
| 307 | else if (is_left) { | ||
| 308 | this_disp.str = ".--"; | ||
| 309 | prev_str = " |"; | ||
| 310 | } else { | ||
| 311 | this_disp.str = "`--"; | ||
| 312 | prev->str = prev_str; | ||
| 313 | } | ||
| 314 | |||
| 315 | show_trunks(&this_disp); | ||
| 316 | if ( root->key >= 'A' && root->key <= 'Z' ) | ||
| 317 | printf("%c\n", root->key); | ||
| 318 | else | ||
| 319 | printf("%d\n", root->key); | ||
| 320 | |||
| 321 | if (prev) prev->str = prev_str; | ||
| 322 | this_disp.str = " |"; | ||
| 323 | |||
| 324 | show_tree(root->left, &this_disp, 0); | ||
| 325 | if (!prev) puts(""); | ||
| 326 | } | ||
| 327 | |||
| 328 | void | ||
| 329 | print(struct tree_node *tree) | ||
| 330 | { | ||
| 331 | if ( tree ) { | ||
| 332 | print(tree->left); | ||
| 333 | printf("%d (%d)\n", tree->key, tree->bal); | ||
| 334 | print(tree->right); | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | int | ||
| 339 | main() | ||
| 340 | { | ||
| 341 | |||
| 342 | |||
| 343 | #if 0 /* 1a/b */ | ||
| 344 | tree = insert(tree, 20); | ||
| 345 | tree = insert(tree, 4); | ||
| 346 | show_tree(tree, 0, 0); | ||
| 347 | |||
| 348 | //tree = insert(tree, 15); | ||
| 349 | tree = insert(tree, 8); | ||
| 350 | show_tree(tree, 0, 0); | ||
| 351 | #endif | ||
| 352 | |||
| 353 | #if 0 /* 2a/b */ | ||
| 354 | tree = insert(tree, 20); | ||
| 355 | tree = insert(tree, 4); | ||
| 356 | tree = insert(tree, 26); | ||
| 357 | tree = insert(tree, 3); | ||
| 358 | tree = insert(tree, 9); | ||
| 359 | show_tree(tree, 0, 0); | ||
| 360 | |||
| 361 | //tree = insert(tree, 15); | ||
| 362 | tree = insert(tree, 8); | ||
| 363 | show_tree(tree, 0, 0); | ||
| 364 | #endif | ||
| 365 | |||
| 366 | #if 0 /* 3a/b */ | ||
| 367 | tree = insert(tree, 20); | ||
| 368 | tree = insert(tree, 4); | ||
| 369 | tree = insert(tree, 26); | ||
| 370 | tree = insert(tree, 3); | ||
| 371 | tree = insert(tree, 9); | ||
| 372 | tree = insert(tree, 21); | ||
| 373 | tree = insert(tree, 30); | ||
| 374 | tree = insert(tree, 2); | ||
| 375 | tree = insert(tree, 7); | ||
| 376 | tree = insert(tree, 11); | ||
| 377 | show_tree(tree, 0, 0); | ||
| 378 | |||
| 379 | //tree = insert(tree, 15); | ||
| 380 | tree = insert(tree, 8); | ||
| 381 | show_tree(tree, 0, 0); | ||
| 382 | #endif | ||
| 383 | |||
| 384 | #if 0 | ||
| 385 | tree = insert(tree, 2); | ||
| 386 | tree = insert(tree, 1); | ||
| 387 | tree = insert(tree, 4); | ||
| 388 | tree = insert(tree, 3); | ||
| 389 | tree = insert(tree, 5); | ||
| 390 | show_tree(tree, 0, 0); | ||
| 391 | |||
| 392 | tree = delete(tree, 1); | ||
| 393 | show_tree(tree, 0, 0); | ||
| 394 | #endif | ||
| 395 | |||
| 396 | #if 0 | ||
| 397 | tree = insert(tree, 6); | ||
| 398 | tree = insert(tree, 2); | ||
| 399 | tree = insert(tree, 9); | ||
| 400 | tree = insert(tree, 1); | ||
| 401 | tree = insert(tree, 4); | ||
| 402 | tree = insert(tree, 8); | ||
| 403 | tree = insert(tree, 'B'); | ||
| 404 | tree = insert(tree, 3); | ||
| 405 | tree = insert(tree, 5); | ||
| 406 | tree = insert(tree, 7); | ||
| 407 | tree = insert(tree, 'A'); | ||
| 408 | tree = insert(tree, 'C'); | ||
| 409 | tree = insert(tree, 'D'); | ||
| 410 | show_tree(tree, 0, 0); | ||
| 411 | |||
| 412 | tree = delete(tree, 1); | ||
| 413 | show_tree(tree, 0, 0); | ||
| 414 | #endif | ||
| 415 | |||
| 416 | |||
| 417 | #if 0 | ||
| 418 | tree = insert(tree, 5); | ||
| 419 | tree = insert(tree, 2); | ||
| 420 | tree = insert(tree, 8); | ||
| 421 | tree = insert(tree, 1); | ||
| 422 | tree = insert(tree, 3); | ||
| 423 | tree = insert(tree, 7); | ||
| 424 | tree = insert(tree, 'A'); | ||
| 425 | tree = insert(tree, 4); | ||
| 426 | tree = insert(tree, 6); | ||
| 427 | tree = insert(tree, 9); | ||
| 428 | tree = insert(tree, 'B'); | ||
| 429 | tree = insert(tree, 'C'); | ||
| 430 | show_tree(tree, 0, 0); | ||
| 431 | |||
| 432 | tree = delete(tree, 1); | ||
| 433 | show_tree(tree, 0, 0); | ||
| 434 | #endif | ||
| 435 | |||
| 436 | |||
| 437 | #if 0 | ||
| 438 | tree = insert(tree, 5); | ||
| 439 | tree = insert(tree, 3); | ||
| 440 | tree = insert(tree, 8); | ||
| 441 | tree = insert(tree, 2); | ||
| 442 | tree = insert(tree, 4); | ||
| 443 | tree = insert(tree, 7); | ||
| 444 | tree = insert(tree, 10); | ||
| 445 | tree = insert(tree, 1); | ||
| 446 | tree = insert(tree, 6); | ||
| 447 | tree = insert(tree, 9); | ||
| 448 | tree = insert(tree, 11); | ||
| 449 | |||
| 450 | tree = delete(tree, 4); | ||
| 451 | tree = delete(tree, 8); | ||
| 452 | tree = delete(tree, 6); | ||
| 453 | tree = delete(tree, 5); | ||
| 454 | tree = delete(tree, 2); | ||
| 455 | tree = delete(tree, 1); | ||
| 456 | tree = delete(tree, 7); | ||
| 457 | |||
| 458 | show_tree(tree, 0, 0); | ||
| 459 | #endif | ||
| 460 | |||
| 461 | struct tree_node *tree = NULL; | ||
| 462 | |||
| 463 | srand(time(NULL)); | ||
| 464 | for ( int i = 0; i != 300000; ++i ) | ||
| 465 | tree = insert(tree, rand()); | ||
| 466 | |||
| 467 | //show_tree(tree, 0, 0); | ||
| 468 | |||
| 469 | return EXIT_SUCCESS; | ||
| 470 | } | ||
| 471 | |||
diff --git a/src/deque.c b/src/deque.c new file mode 100644 index 0000000..881d1d3 --- /dev/null +++ b/src/deque.c | |||
| @@ -0,0 +1,485 @@ | |||
| 1 | #include <assert.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <stdlib.h> | ||
| 5 | |||
| 6 | #include "util.h" | ||
| 7 | |||
| 8 | #define START_MAP_CAPACITY 4 | ||
| 9 | #define CHUNK_CAPACITY 17 | ||
| 10 | |||
| 11 | /* --8<-- deque_type */ | ||
| 12 | typedef int T; | ||
| 13 | |||
| 14 | struct deque { | ||
| 15 | T **map; | ||
| 16 | |||
| 17 | size_t map_begin; | ||
| 18 | size_t map_end; | ||
| 19 | size_t map_capacity; | ||
| 20 | |||
| 21 | size_t offset; | ||
| 22 | size_t size; | ||
| 23 | }; | ||
| 24 | /* -->8-- */ | ||
| 25 | |||
| 26 | /* --8<-- deque_allocate */ | ||
| 27 | static void * | ||
| 28 | allocate(size_t n, size_t sz) | ||
| 29 | { | ||
| 30 | void *ptr = calloc(n, sz); | ||
| 31 | if ( ptr == NULL ) { | ||
| 32 | ERROR("out of memory!"); | ||
| 33 | } | ||
| 34 | return ptr; | ||
| 35 | } | ||
| 36 | /* -->8-- */ | ||
| 37 | |||
| 38 | /* --8<-- deque_init */ | ||
| 39 | void | ||
| 40 | deque_init(struct deque *d) | ||
| 41 | { | ||
| 42 | assert(d); | ||
| 43 | |||
| 44 | d->map_begin = 0; | ||
| 45 | d->map_end = 0; | ||
| 46 | d->offset = 0; | ||
| 47 | d->size = 0; | ||
| 48 | |||
| 49 | // TODO: Error handling | ||
| 50 | d->map = allocate(START_MAP_CAPACITY, sizeof *d->map); | ||
| 51 | if ( d->map ) { | ||
| 52 | d->map_capacity = START_MAP_CAPACITY; | ||
| 53 | |||
| 54 | for ( size_t i = 0; i != d->map_capacity; ++i ) { | ||
| 55 | d->map[i] = NULL; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | /* -->8-- */ | ||
| 60 | |||
| 61 | /* --8<-- deque_free */ | ||
| 62 | void | ||
| 63 | deque_free(struct deque *d) | ||
| 64 | { | ||
| 65 | assert(d); | ||
| 66 | |||
| 67 | // free all chunks | ||
| 68 | for ( size_t i = 0; i != d->map_capacity; ++i ) { | ||
| 69 | free(d->map[i]); | ||
| 70 | } | ||
| 71 | |||
| 72 | // free the map itself | ||
| 73 | free(d->map); | ||
| 74 | d->map = NULL; | ||
| 75 | } | ||
| 76 | /* -->8-- */ | ||
| 77 | |||
| 78 | /* --8<-- deque_size */ | ||
| 79 | size_t | ||
| 80 | deque_size(struct deque *d) | ||
| 81 | { | ||
| 82 | assert(d); | ||
| 83 | |||
| 84 | return d->size; | ||
| 85 | } | ||
| 86 | /* -->8-- */ | ||
| 87 | |||
| 88 | /* --8<-- deque_is_empty */ | ||
| 89 | bool | ||
| 90 | deque_is_empty(struct deque *d) | ||
| 91 | { | ||
| 92 | assert(d); | ||
| 93 | |||
| 94 | return d->map_begin == d->map_end; | ||
| 95 | } | ||
| 96 | /* -->8-- */ | ||
| 97 | |||
| 98 | /* --8<-- deque_grow_map */ | ||
| 99 | static void | ||
| 100 | grow_map(struct deque *d) | ||
| 101 | { | ||
| 102 | assert(d); | ||
| 103 | |||
| 104 | const size_t capacity = d->map_capacity + d->map_capacity / 2; | ||
| 105 | T ** map = allocate(capacity, sizeof *map); | ||
| 106 | |||
| 107 | // copy elements | ||
| 108 | size_t i, j; | ||
| 109 | for ( i = 0, j = d->map_begin; i != d->map_capacity; ++i, ++j ) { | ||
| 110 | if ( j == d->map_capacity ) { | ||
| 111 | j = 0; | ||
| 112 | } | ||
| 113 | map[i] = d->map[j]; | ||
| 114 | } | ||
| 115 | |||
| 116 | // initialize the rest (new) elements with NULL | ||
| 117 | for ( ; i != capacity; ++i ) { | ||
| 118 | map[i] = NULL; | ||
| 119 | } | ||
| 120 | |||
| 121 | // free old & assign new map | ||
| 122 | free(d->map); | ||
| 123 | d->map = map; | ||
| 124 | |||
| 125 | // adjust pointers | ||
| 126 | d->map_begin = 0; | ||
| 127 | d->map_end = d->map_capacity - 1; | ||
| 128 | |||
| 129 | // set new map_capacity | ||
| 130 | d->map_capacity = capacity; | ||
| 131 | } | ||
| 132 | /* -->8-- */ | ||
| 133 | |||
| 134 | /* --8<-- deque_map_append_chunk */ | ||
| 135 | static void | ||
| 136 | map_append_chunk(struct deque *d) | ||
| 137 | { | ||
| 138 | assert(d); | ||
| 139 | |||
| 140 | size_t next = (d->map_end + 1) % d->map_capacity; | ||
| 141 | |||
| 142 | if ( next == d->map_begin ) { // Resize the map | ||
| 143 | grow_map(d); | ||
| 144 | |||
| 145 | next = d->map_end + 1; | ||
| 146 | } | ||
| 147 | |||
| 148 | d->map[d->map_end] = allocate(CHUNK_CAPACITY, sizeof **d->map); | ||
| 149 | d->map_end = next; | ||
| 150 | } | ||
| 151 | /* -->8-- */ | ||
| 152 | |||
| 153 | /* --8<-- deque_map_prepend_chunk */ | ||
| 154 | static void | ||
| 155 | map_prepend_chunk(struct deque *d) | ||
| 156 | { | ||
| 157 | assert(d); | ||
| 158 | |||
| 159 | size_t prev = (d->map_begin + d->map_capacity - 1) % d->map_capacity; | ||
| 160 | |||
| 161 | if ( prev == d->map_end ) { | ||
| 162 | grow_map(d); | ||
| 163 | |||
| 164 | prev = d->map_capacity - 1; | ||
| 165 | } | ||
| 166 | |||
| 167 | d->map[prev] = allocate(CHUNK_CAPACITY, sizeof **d->map); | ||
| 168 | d->map_begin = prev; | ||
| 169 | } | ||
| 170 | /* -->8-- */ | ||
| 171 | |||
| 172 | /* --8<-- deque_map_remove_front_chunk */ | ||
| 173 | static void | ||
| 174 | map_remove_front_chunk(struct deque *d) | ||
| 175 | { | ||
| 176 | assert(d); | ||
| 177 | |||
| 178 | if ( d->map_begin == d->map_end ) { | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | |||
| 182 | const size_t next = (d->map_begin + 1) % d->map_capacity; | ||
| 183 | |||
| 184 | free(d->map[d->map_begin]); | ||
| 185 | d->map[d->map_begin] = NULL; | ||
| 186 | |||
| 187 | d->map_begin = next; | ||
| 188 | } | ||
| 189 | /* -->8-- */ | ||
| 190 | |||
| 191 | /* --8<-- deque_remove_tail_chunk */ | ||
| 192 | static void | ||
| 193 | map_remove_tail_chunk(struct deque *d) | ||
| 194 | { | ||
| 195 | assert(d); | ||
| 196 | |||
| 197 | if ( d->map_begin == d->map_end ) { | ||
| 198 | return; | ||
| 199 | } | ||
| 200 | |||
| 201 | const size_t prev = (d->map_end + d->map_capacity - 1) % d->map_capacity; | ||
| 202 | |||
| 203 | free(d->map[prev]); | ||
| 204 | d->map[prev] = NULL; | ||
| 205 | |||
| 206 | d->map_end = prev; | ||
| 207 | } | ||
| 208 | /* -->8-- */ | ||
| 209 | |||
| 210 | /* --8<-- deque_get_at */ | ||
| 211 | bool | ||
| 212 | deque_get_at(struct deque *d, size_t idx, T *data) | ||
| 213 | { | ||
| 214 | assert(d); | ||
| 215 | assert(idx < d->size); | ||
| 216 | assert(data); | ||
| 217 | |||
| 218 | if ( idx >= d->size ) { | ||
| 219 | return false; | ||
| 220 | } | ||
| 221 | |||
| 222 | const size_t pos = d->offset + idx; | ||
| 223 | const size_t chunk_off = pos % CHUNK_CAPACITY; | ||
| 224 | const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity; | ||
| 225 | |||
| 226 | *data = d->map[chunk_num][chunk_off]; | ||
| 227 | |||
| 228 | return true; | ||
| 229 | } | ||
| 230 | /* -->8-- */ | ||
| 231 | |||
| 232 | /* --8<-- deque_set_at */ | ||
| 233 | bool | ||
| 234 | deque_set_at(struct deque *d, size_t idx, T data) | ||
| 235 | { | ||
| 236 | assert(d); | ||
| 237 | assert(idx < d->size); | ||
| 238 | |||
| 239 | if ( idx >= d->size ) { | ||
| 240 | return false; | ||
| 241 | } | ||
| 242 | |||
| 243 | const size_t pos = d->offset + idx; | ||
| 244 | const size_t chunk_off = pos % CHUNK_CAPACITY; | ||
| 245 | const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity; | ||
| 246 | |||
| 247 | d->map[chunk_num][chunk_off] = data; | ||
| 248 | |||
| 249 | return true; | ||
| 250 | } | ||
| 251 | /* -->8-- */ | ||
| 252 | |||
| 253 | /* --8<-- deque_push_back */ | ||
| 254 | void | ||
| 255 | deque_push_back(struct deque *d, T data) | ||
| 256 | { | ||
| 257 | assert(d); | ||
| 258 | |||
| 259 | const size_t pos = d->offset + d->size; | ||
| 260 | const size_t chunk_off = pos % CHUNK_CAPACITY; | ||
| 261 | size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity; | ||
| 262 | |||
| 263 | if ( chunk_num == d->map_end ) { | ||
| 264 | map_append_chunk(d); | ||
| 265 | chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity; | ||
| 266 | } | ||
| 267 | |||
| 268 | d->map[chunk_num][chunk_off] = data; | ||
| 269 | ++d->size; | ||
| 270 | } | ||
| 271 | /* -->8-- */ | ||
| 272 | |||
| 273 | /* --8<-- deque_push_front */ | ||
| 274 | void | ||
| 275 | deque_push_front(struct deque *d, T data) | ||
| 276 | { | ||
| 277 | assert(d); | ||
| 278 | |||
| 279 | if ( d->offset == 0 ) { // Im ersten Element ist kein Platz mehr frei! | ||
| 280 | map_prepend_chunk(d); | ||
| 281 | d->offset = CHUNK_CAPACITY; | ||
| 282 | } | ||
| 283 | |||
| 284 | --d->offset; | ||
| 285 | |||
| 286 | const size_t chunk_num = (d->offset / CHUNK_CAPACITY + d->map_begin) % d->map_capacity; | ||
| 287 | |||
| 288 | d->map[chunk_num][d->offset] = data; | ||
| 289 | ++d->size; | ||
| 290 | } | ||
| 291 | /* -->8-- */ | ||
| 292 | |||
| 293 | /* --8<-- deque_pop_back */ | ||
| 294 | bool | ||
| 295 | deque_pop_back(struct deque *d, T *data) | ||
| 296 | { | ||
| 297 | assert(d); | ||
| 298 | assert(data); | ||
| 299 | |||
| 300 | if ( d->size == 0 ) { | ||
| 301 | return false; | ||
| 302 | } | ||
| 303 | |||
| 304 | --d->size; | ||
| 305 | |||
| 306 | const size_t pos = d->offset + d->size; | ||
| 307 | const size_t chunk_off = pos % CHUNK_CAPACITY; | ||
| 308 | const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity; | ||
| 309 | |||
| 310 | *data = d->map[chunk_num][chunk_off]; | ||
| 311 | |||
| 312 | if ( d->size == 0 || chunk_off == 0 ) { | ||
| 313 | map_remove_tail_chunk(d); | ||
| 314 | } | ||
| 315 | |||
| 316 | return true; | ||
| 317 | } | ||
| 318 | /* -->8-- */ | ||
| 319 | |||
| 320 | /* --8<-- deque_pop_front */ | ||
| 321 | bool | ||
| 322 | deque_pop_front(struct deque *d, T *data) | ||
| 323 | { | ||
| 324 | assert(d); | ||
| 325 | assert(data); | ||
| 326 | |||
| 327 | if ( d->size == 0 ) { | ||
| 328 | return false; | ||
| 329 | } | ||
| 330 | |||
| 331 | --d->size; | ||
| 332 | |||
| 333 | const size_t chunk_num = (d->offset / CHUNK_CAPACITY + d->map_begin) % d->map_capacity; | ||
| 334 | |||
| 335 | *data = d->map[chunk_num][d->offset]; | ||
| 336 | |||
| 337 | ++d->offset; | ||
| 338 | |||
| 339 | if ( d->size == 0 || d->offset == CHUNK_CAPACITY ) { | ||
| 340 | map_remove_front_chunk(d); | ||
| 341 | d->offset = 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | return true; | ||
| 345 | } | ||
| 346 | /* -->8-- */ | ||
| 347 | |||
| 348 | static void | ||
| 349 | deque_show(struct deque *d) | ||
| 350 | { | ||
| 351 | assert(d); | ||
| 352 | |||
| 353 | printf("first: %zu -- last: %zu -- size: %zu -- map_capacity: %zu -- offset: %zu\n", | ||
| 354 | d->map_begin, d->map_end, d->size, d->map_capacity, d->offset); | ||
| 355 | for ( size_t i = 0; i != d->map_capacity; ++i ) { | ||
| 356 | printf("%zu(%p) ", i, (void *) d->map[i]); | ||
| 357 | } | ||
| 358 | putchar('\n'); | ||
| 359 | } | ||
| 360 | |||
| 361 | void | ||
| 362 | test_deque(void) | ||
| 363 | { | ||
| 364 | #ifndef NDEBUG | ||
| 365 | struct deque d[1]; | ||
| 366 | |||
| 367 | deque_init(d); | ||
| 368 | |||
| 369 | const int N = 100000; | ||
| 370 | |||
| 371 | for ( int i = 0; i != N; ++i ) { | ||
| 372 | deque_push_front(d, i); | ||
| 373 | } | ||
| 374 | |||
| 375 | for ( int i = 0; i != N; ++i ) { | ||
| 376 | int data; | ||
| 377 | assert(deque_pop_back(d, &data) == true); | ||
| 378 | assert(data == i); | ||
| 379 | } | ||
| 380 | assert(deque_is_empty(d) == true); | ||
| 381 | assert(deque_size(d) == 0); | ||
| 382 | |||
| 383 | deque_free(d); | ||
| 384 | |||
| 385 | deque_init(d); | ||
| 386 | |||
| 387 | for ( int i = 0; i != N; ++i ) { | ||
| 388 | deque_push_back(d, i); | ||
| 389 | } | ||
| 390 | |||
| 391 | for ( int i = 0; i != N; ++i ) { | ||
| 392 | int data; | ||
| 393 | assert(deque_pop_front(d, &data) == true); | ||
| 394 | assert(data == i); | ||
| 395 | } | ||
| 396 | assert(deque_is_empty(d) == true); | ||
| 397 | assert(deque_size(d) == 0); | ||
| 398 | |||
| 399 | deque_free(d); | ||
| 400 | |||
| 401 | deque_init(d); | ||
| 402 | |||
| 403 | for ( int i = 0; i != N; ++i ) { | ||
| 404 | deque_push_back(d, i); | ||
| 405 | } | ||
| 406 | |||
| 407 | for ( int i = N - 1; i >= 0; --i ) { | ||
| 408 | int data; | ||
| 409 | assert(deque_pop_back(d, &data) == true); | ||
| 410 | assert(data == i); | ||
| 411 | } | ||
| 412 | assert(deque_is_empty(d) == true); | ||
| 413 | assert(deque_size(d) == 0); | ||
| 414 | |||
| 415 | deque_free(d); | ||
| 416 | |||
| 417 | deque_init(d); | ||
| 418 | |||
| 419 | for ( int i = 0; i != N; ++i ) { | ||
| 420 | if ( i & 1 ) { | ||
| 421 | deque_push_front(d, i); | ||
| 422 | } | ||
| 423 | else { | ||
| 424 | deque_push_back(d, i); | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | for ( int i = N - 1; i >= 0; --i ) { | ||
| 429 | int data; | ||
| 430 | if ( i & 1 ) { | ||
| 431 | assert(deque_pop_front(d, &data) == true); | ||
| 432 | } | ||
| 433 | else { | ||
| 434 | assert(deque_pop_back(d, &data) == true); | ||
| 435 | } | ||
| 436 | if ( data != i ) { | ||
| 437 | printf("i: %d - data: %d\n", i, data); | ||
| 438 | } | ||
| 439 | assert(data == i); | ||
| 440 | } | ||
| 441 | assert(deque_is_empty(d) == true); | ||
| 442 | assert(deque_size(d) == 0); | ||
| 443 | |||
| 444 | deque_free(d); | ||
| 445 | |||
| 446 | deque_init(d); | ||
| 447 | |||
| 448 | for ( int i = 0; i != N; ++i ) { | ||
| 449 | deque_push_front(d, i); | ||
| 450 | } | ||
| 451 | |||
| 452 | for ( int i = N - 1; i >= 0; --i ) { | ||
| 453 | int data; | ||
| 454 | assert(deque_pop_front(d, &data) == true); | ||
| 455 | assert(data == i); | ||
| 456 | } | ||
| 457 | assert(deque_is_empty(d) == true); | ||
| 458 | assert(deque_size(d) == 0); | ||
| 459 | |||
| 460 | deque_free(d); | ||
| 461 | |||
| 462 | puts("all tests passed."); | ||
| 463 | #endif | ||
| 464 | } | ||
| 465 | |||
| 466 | int | ||
| 467 | main(void) | ||
| 468 | { | ||
| 469 | test_deque(); | ||
| 470 | |||
| 471 | struct deque c; | ||
| 472 | |||
| 473 | deque_init(&c); | ||
| 474 | |||
| 475 | T data; | ||
| 476 | while ( deque_pop_front(&c, &data) ) { | ||
| 477 | printf("%u, ", data); | ||
| 478 | } | ||
| 479 | putchar('\n'); | ||
| 480 | deque_show(&c); | ||
| 481 | |||
| 482 | deque_free(&c); | ||
| 483 | |||
| 484 | return 0; | ||
| 485 | } | ||
diff --git a/src/dlist.c b/src/dlist.c new file mode 100644 index 0000000..55e42d7 --- /dev/null +++ b/src/dlist.c | |||
| @@ -0,0 +1,504 @@ | |||
| 1 | /* dlist -- double linked list */ | ||
| 2 | |||
| 3 | /* Standard C */ | ||
| 4 | #include <assert.h> | ||
| 5 | #include <stdbool.h> | ||
| 6 | #include <stdio.h> | ||
| 7 | #include <stdlib.h> | ||
| 8 | #include <time.h> | ||
| 9 | |||
| 10 | /* Project */ | ||
| 11 | #include "util.h" | ||
| 12 | |||
| 13 | /* --8<-- dlist_type */ | ||
| 14 | typedef int T; | ||
| 15 | |||
| 16 | struct dlist { | ||
| 17 | struct dlist_element *head, *tail; | ||
| 18 | }; | ||
| 19 | |||
| 20 | struct dlist_element { | ||
| 21 | struct dlist_element *prev, *next; | ||
| 22 | T data; | ||
| 23 | }; | ||
| 24 | /* -->8-- */ | ||
| 25 | |||
| 26 | /* --8<-- dlist_init */ | ||
| 27 | void | ||
| 28 | dlist_init(struct dlist *dlist) | ||
| 29 | { | ||
| 30 | dlist->head = NULL; | ||
| 31 | dlist->tail = NULL; | ||
| 32 | } | ||
| 33 | /* -->8-- */ | ||
| 34 | |||
| 35 | /* --8<-- dlist_empty */ | ||
| 36 | bool | ||
| 37 | dlist_empty(struct dlist *dlist) | ||
| 38 | { | ||
| 39 | return dlist->head == NULL; | ||
| 40 | } | ||
| 41 | /* -->8-- */ | ||
| 42 | |||
| 43 | /* --8<-- dlist_create_element */ | ||
| 44 | static struct dlist_element * | ||
| 45 | create_element(T data) | ||
| 46 | { | ||
| 47 | struct dlist_element *element; | ||
| 48 | |||
| 49 | element = malloc(sizeof *element); | ||
| 50 | if ( element ) { | ||
| 51 | element->data = data; | ||
| 52 | } | ||
| 53 | |||
| 54 | return element; | ||
| 55 | } | ||
| 56 | /* -->8-- */ | ||
| 57 | |||
| 58 | /* --8<-- dlist_push_front */ | ||
| 59 | struct dlist_element * | ||
| 60 | dlist_push_front(struct dlist *dlist, T data) | ||
| 61 | { | ||
| 62 | struct dlist_element *element; | ||
| 63 | |||
| 64 | element = create_element(data); | ||
| 65 | if ( element ) { | ||
| 66 | element->prev = NULL; /* Vorgänger ist in jedem Fall NULL */ | ||
| 67 | |||
| 68 | if ( dlist_empty(dlist) ) { | ||
| 69 | element->next = NULL; | ||
| 70 | dlist->tail = element; | ||
| 71 | } | ||
| 72 | else { | ||
| 73 | element->next = dlist->head; | ||
| 74 | element->next->prev = element; | ||
| 75 | } | ||
| 76 | |||
| 77 | dlist->head = element; /* Neues Element ist in jedem Fall der neue Anfang! */ | ||
| 78 | } | ||
| 79 | else | ||
| 80 | ERROR("out of memory"); | ||
| 81 | |||
| 82 | return element; | ||
| 83 | } | ||
| 84 | /* -->8-- */ | ||
| 85 | |||
| 86 | /* --8<-- dlist_push_back */ | ||
| 87 | struct dlist_element * | ||
| 88 | dlist_push_back(struct dlist *dlist, T data) | ||
| 89 | { | ||
| 90 | struct dlist_element *element; | ||
| 91 | |||
| 92 | element = create_element(data); | ||
| 93 | if ( element ) { | ||
| 94 | element->next = NULL; /* Nachfolger ist in jedem Fall NULL */ | ||
| 95 | |||
| 96 | if ( dlist_empty(dlist) ) { | ||
| 97 | element->prev = NULL; | ||
| 98 | dlist->head = element; | ||
| 99 | } | ||
| 100 | else { | ||
| 101 | element->prev = dlist->tail; | ||
| 102 | element->prev->next = element; | ||
| 103 | } | ||
| 104 | |||
| 105 | dlist->tail = element; /* Neues Element ist in jedem Fall das neue Ende! */ | ||
| 106 | } | ||
| 107 | else | ||
| 108 | ERROR("out of memory"); | ||
| 109 | |||
| 110 | return element; | ||
| 111 | } | ||
| 112 | /* -->8-- */ | ||
| 113 | |||
| 114 | /* --8<-- dlist_pop_front */ | ||
| 115 | bool | ||
| 116 | dlist_pop_front(struct dlist *dlist, T *data) | ||
| 117 | { | ||
| 118 | if ( dlist->head ) { | ||
| 119 | struct dlist_element *element = dlist->head; | ||
| 120 | |||
| 121 | dlist->head = element->next; | ||
| 122 | |||
| 123 | if ( dlist->head == NULL ) | ||
| 124 | dlist->tail = NULL; | ||
| 125 | else | ||
| 126 | element->next->prev = NULL; | ||
| 127 | |||
| 128 | if ( data ) { | ||
| 129 | *data = element->data; | ||
| 130 | } | ||
| 131 | free(element); | ||
| 132 | |||
| 133 | return true; | ||
| 134 | } | ||
| 135 | else | ||
| 136 | return false; | ||
| 137 | } | ||
| 138 | /* -->8-- */ | ||
| 139 | |||
| 140 | /* --8<-- dlist_pop_back */ | ||
| 141 | bool | ||
| 142 | dlist_pop_back(struct dlist *dlist, T *data) | ||
| 143 | { | ||
| 144 | if ( dlist->head ) { | ||
| 145 | struct dlist_element *element = dlist->tail; | ||
| 146 | |||
| 147 | dlist->tail = element->prev; | ||
| 148 | |||
| 149 | if ( dlist->tail == NULL ) | ||
| 150 | dlist->head = NULL; | ||
| 151 | else | ||
| 152 | element->prev->next = NULL; | ||
| 153 | |||
| 154 | if ( data ) { | ||
| 155 | *data = element->data; | ||
| 156 | } | ||
| 157 | free(element); | ||
| 158 | |||
| 159 | return true; | ||
| 160 | } | ||
| 161 | else | ||
| 162 | return false; | ||
| 163 | } | ||
| 164 | /* -->8-- */ | ||
| 165 | |||
| 166 | /* --8<-- dlist_insert_next */ | ||
| 167 | struct dlist_element * | ||
| 168 | dlist_insert_next(struct dlist *dlist, struct dlist_element *element, T data) | ||
| 169 | { | ||
| 170 | struct dlist_element *new_element; | ||
| 171 | |||
| 172 | new_element = create_element(data); | ||
| 173 | if ( new_element ) { | ||
| 174 | if ( dlist->head == NULL ) { | ||
| 175 | dlist->head = new_element; | ||
| 176 | dlist->head->prev = NULL; | ||
| 177 | dlist->head->next = NULL; | ||
| 178 | dlist->tail = new_element; | ||
| 179 | } | ||
| 180 | else { | ||
| 181 | new_element->next = element->next; | ||
| 182 | new_element->prev = element; | ||
| 183 | |||
| 184 | if ( element->next == NULL ) | ||
| 185 | dlist->tail = new_element; | ||
| 186 | else | ||
| 187 | element->next->prev = new_element; | ||
| 188 | |||
| 189 | element->next = new_element; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | else | ||
| 193 | ERROR("out of memory"); | ||
| 194 | |||
| 195 | return new_element; | ||
| 196 | } | ||
| 197 | /* -->8-- */ | ||
| 198 | |||
| 199 | /* --8<-- dlist_insert_prev */ | ||
| 200 | struct dlist_element * | ||
| 201 | dlist_insert_prev(struct dlist *dlist, struct dlist_element *element, T data) | ||
| 202 | { | ||
| 203 | struct dlist_element *new_element; | ||
| 204 | |||
| 205 | new_element = create_element(data); | ||
| 206 | if ( new_element ) { | ||
| 207 | if ( dlist->head == NULL ) { | ||
| 208 | dlist->head = new_element; | ||
| 209 | dlist->head->prev = NULL; | ||
| 210 | dlist->head->next = NULL; | ||
| 211 | dlist->tail = new_element; | ||
| 212 | } | ||
| 213 | else { | ||
| 214 | new_element->next = element; | ||
| 215 | new_element->prev = element->prev; | ||
| 216 | |||
| 217 | if ( element->prev == NULL ) | ||
| 218 | dlist->head = new_element; | ||
| 219 | else | ||
| 220 | element->prev->next = new_element; | ||
| 221 | |||
| 222 | element->prev = new_element; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | else | ||
| 226 | ERROR("out of memory"); | ||
| 227 | |||
| 228 | return new_element; | ||
| 229 | } | ||
| 230 | /* -->8-- */ | ||
| 231 | |||
| 232 | /* --8<-- dlist_remove */ | ||
| 233 | void | ||
| 234 | dlist_remove(struct dlist *dlist, struct dlist_element *element) | ||
| 235 | { | ||
| 236 | if ( element == dlist->head ) { | ||
| 237 | dlist->head = element->next; | ||
| 238 | |||
| 239 | if ( dlist->head == NULL ) | ||
| 240 | dlist->tail = NULL; | ||
| 241 | else | ||
| 242 | element->next->prev = NULL; | ||
| 243 | } | ||
| 244 | else { | ||
| 245 | element->prev->next = element->next; | ||
| 246 | |||
| 247 | if ( element->next == NULL ) | ||
| 248 | dlist->tail = element->prev; | ||
| 249 | else | ||
| 250 | element->next->prev = element->prev; | ||
| 251 | } | ||
| 252 | |||
| 253 | free(element); | ||
| 254 | } | ||
| 255 | /* -->8-- */ | ||
| 256 | |||
| 257 | /* --8<-- dlist_free */ | ||
| 258 | void | ||
| 259 | dlist_free(struct dlist *dlist) | ||
| 260 | { | ||
| 261 | struct dlist_element *elem, *next; | ||
| 262 | |||
| 263 | for ( elem = dlist->head; elem; elem = next ) { | ||
| 264 | next = elem->next; | ||
| 265 | free(elem); | ||
| 266 | } | ||
| 267 | |||
| 268 | dlist_init(dlist); | ||
| 269 | } | ||
| 270 | /* -->8-- */ | ||
| 271 | |||
| 272 | void | ||
| 273 | dlist_apply_rev(struct dlist *dlist, void (*visit)(T data, void *cl), void *cl) | ||
| 274 | { | ||
| 275 | for ( struct dlist_element *elem = dlist->tail; elem; elem = elem->prev ) { | ||
| 276 | visit(elem->data, cl); | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | void | ||
| 281 | print_list(const char *msg, struct dlist *dlist) | ||
| 282 | { | ||
| 283 | printf("%s:", msg); | ||
| 284 | |||
| 285 | for ( struct dlist_element *elem = dlist->head; elem; elem = elem->next ) | ||
| 286 | printf(" %d", elem->data); | ||
| 287 | |||
| 288 | putchar('\n'); | ||
| 289 | } | ||
| 290 | |||
| 291 | void | ||
| 292 | print_list_rev(const char *msg, struct dlist *dlist) | ||
| 293 | { | ||
| 294 | printf("%s:", msg); | ||
| 295 | |||
| 296 | for ( struct dlist_element *elem = dlist->tail; elem; elem = elem->prev ) | ||
| 297 | printf(" %d", elem->data); | ||
| 298 | |||
| 299 | putchar('\n'); | ||
| 300 | } | ||
| 301 | |||
| 302 | void | ||
| 303 | remove_if(struct dlist *list) | ||
| 304 | { | ||
| 305 | struct dlist_element *elem, *next; | ||
| 306 | |||
| 307 | for ( elem = list->head; elem; elem = next ) { | ||
| 308 | next = elem->next; | ||
| 309 | |||
| 310 | if ( (elem->data & 1) == 1 ) { | ||
| 311 | dlist_remove(list, elem); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | /* --8<-- dlist_merge */ | ||
| 317 | struct dlist * | ||
| 318 | dlist_merge(struct dlist *list1, struct dlist *list2) | ||
| 319 | { | ||
| 320 | struct dlist_element *head = NULL, | ||
| 321 | *cur = NULL, | ||
| 322 | *e1 = list1->head, | ||
| 323 | *e2 = list2->head; | ||
| 324 | |||
| 325 | while ( e1 && e2 ) // Solange in e1 UND e2 Elemente sind... | ||
| 326 | { | ||
| 327 | if ( e1->data < e2->data ) { | ||
| 328 | e1->prev = cur; | ||
| 329 | if ( cur ) | ||
| 330 | cur->next = e1; | ||
| 331 | else | ||
| 332 | head = e1; | ||
| 333 | cur = e1; | ||
| 334 | e1 = e1->next; | ||
| 335 | } | ||
| 336 | else { | ||
| 337 | e2->prev = cur; | ||
| 338 | if ( cur ) | ||
| 339 | cur->next = e2; | ||
| 340 | else | ||
| 341 | head = e2; | ||
| 342 | cur = e2; | ||
| 343 | e2 = e2->next; | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | if ( e1 ) // in e1 sind noch Elemente vorhanden! | ||
| 348 | { | ||
| 349 | assert(e2 == NULL); | ||
| 350 | |||
| 351 | e1->prev = cur; | ||
| 352 | if ( cur ) | ||
| 353 | cur->next = e1; | ||
| 354 | else | ||
| 355 | head = e1; | ||
| 356 | |||
| 357 | // list1->tail zeigt bereits auf das letzte Element in list1 | ||
| 358 | } | ||
| 359 | else /* if ( e2 ) */ | ||
| 360 | { | ||
| 361 | assert(e1 == NULL); | ||
| 362 | assert(e2); | ||
| 363 | |||
| 364 | e2->prev = cur; | ||
| 365 | if ( cur ) | ||
| 366 | cur->next = e2; | ||
| 367 | else | ||
| 368 | head = e2; | ||
| 369 | |||
| 370 | list1->tail = list2->tail; // list2->tail ist das Ende der Liste | ||
| 371 | } | ||
| 372 | |||
| 373 | // Kopf neu setzen... | ||
| 374 | list1->head = head; | ||
| 375 | |||
| 376 | // Liste2 ist leer | ||
| 377 | list2->head = NULL; | ||
| 378 | list2->tail = NULL; | ||
| 379 | |||
| 380 | // Zeiger auf Liste1 zurückliefern | ||
| 381 | return list1; | ||
| 382 | } | ||
| 383 | /* -->8-- */ | ||
| 384 | |||
| 385 | /* --8<-- dlist_sort */ | ||
| 386 | struct dlist * | ||
| 387 | dlist_sort(struct dlist *list) | ||
| 388 | { | ||
| 389 | if ( list->head == NULL || list->head->next == NULL ) // Leer oder nur ein Element? => Fertig | ||
| 390 | return list; | ||
| 391 | |||
| 392 | struct dlist_element *slow = list->head, | ||
| 393 | *fast = list->head->next; | ||
| 394 | |||
| 395 | while ( fast && fast->next ) | ||
| 396 | slow = slow->next, fast = fast->next->next; | ||
| 397 | |||
| 398 | struct dlist list1 = { .head = list->head, .tail = slow }, | ||
| 399 | list2 = { .head = slow->next, .tail = list->tail }; | ||
| 400 | |||
| 401 | list1.tail->next = list2.head->prev = NULL; | ||
| 402 | |||
| 403 | dlist_merge(dlist_sort(&list1), dlist_sort(&list2)); | ||
| 404 | |||
| 405 | list->head = list1.head; | ||
| 406 | list->tail = list1.tail; | ||
| 407 | |||
| 408 | return list; | ||
| 409 | } | ||
| 410 | /* -->8-- */ | ||
| 411 | |||
| 412 | void | ||
| 413 | merge_test(void) | ||
| 414 | { | ||
| 415 | struct dlist l1, l2; | ||
| 416 | |||
| 417 | dlist_init(&l1); | ||
| 418 | dlist_init(&l2); | ||
| 419 | |||
| 420 | dlist_push_back(&l1, 7); | ||
| 421 | dlist_push_back(&l1, 10); | ||
| 422 | dlist_push_back(&l1, 11); | ||
| 423 | dlist_push_back(&l1, 19); | ||
| 424 | dlist_push_back(&l1, 23); | ||
| 425 | |||
| 426 | dlist_push_back(&l2, 4); | ||
| 427 | dlist_push_back(&l2, 14); | ||
| 428 | dlist_push_back(&l2, 15); | ||
| 429 | |||
| 430 | struct dlist *ptr; | ||
| 431 | ptr = dlist_merge(&l1, &l2); | ||
| 432 | |||
| 433 | struct dlist_element *cur; | ||
| 434 | for ( cur = ptr->head; cur; cur = cur->next ) { | ||
| 435 | if ( cur->prev ) | ||
| 436 | printf("%4d", cur->prev->data); | ||
| 437 | else | ||
| 438 | printf("xxx "); | ||
| 439 | printf("%4d", cur->data); | ||
| 440 | if ( cur->next ) | ||
| 441 | printf("%4d", cur->next->data); | ||
| 442 | else | ||
| 443 | printf(" xxx"); | ||
| 444 | |||
| 445 | puts(""); | ||
| 446 | } | ||
| 447 | |||
| 448 | dlist_free(&l1); | ||
| 449 | dlist_free(&l2); | ||
| 450 | } | ||
| 451 | |||
| 452 | void | ||
| 453 | ls() | ||
| 454 | { | ||
| 455 | struct dlist list; | ||
| 456 | |||
| 457 | dlist_init(&list); | ||
| 458 | |||
| 459 | for ( int i = 0; i != 30000000; ++i ) | ||
| 460 | dlist_insert_prev(&list, list.tail, rand() % 9999); | ||
| 461 | |||
| 462 | //print_list("Unsortiert:", &list); | ||
| 463 | printf("start\n"); | ||
| 464 | clock_t start = clock(); | ||
| 465 | dlist_sort(&list); | ||
| 466 | clock_t ende = clock(); | ||
| 467 | |||
| 468 | printf("Dauer: %.3fsec\n", ((double) ende - start) / CLOCKS_PER_SEC); | ||
| 469 | //print_list("Sortiert:", &list); | ||
| 470 | //print_list_rev("Sortiert:", &list); | ||
| 471 | |||
| 472 | dlist_free(&list); | ||
| 473 | } | ||
| 474 | |||
| 475 | int | ||
| 476 | main(void) | ||
| 477 | { | ||
| 478 | ls(); | ||
| 479 | |||
| 480 | #if 0 | ||
| 481 | merge_test(); | ||
| 482 | #endif | ||
| 483 | |||
| 484 | #if 0 | ||
| 485 | struct dlist list; | ||
| 486 | |||
| 487 | dlist_init(&list); | ||
| 488 | |||
| 489 | for ( int i = 0; i != 10; ++i ) | ||
| 490 | dlist_insert_prev(&list, list.tail, i); | ||
| 491 | |||
| 492 | print_list("Ausgabe: ", &list); | ||
| 493 | |||
| 494 | remove_if(&list); | ||
| 495 | |||
| 496 | print_list("Ausgabe: ", &list); | ||
| 497 | |||
| 498 | dlist_free(&list); | ||
| 499 | |||
| 500 | ls(); | ||
| 501 | |||
| 502 | return EXIT_SUCCESS; | ||
| 503 | #endif | ||
| 504 | } | ||
diff --git a/src/hashtab.c b/src/hashtab.c new file mode 100644 index 0000000..256fac9 --- /dev/null +++ b/src/hashtab.c | |||
| @@ -0,0 +1,220 @@ | |||
| 1 | #include <ctype.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <stdlib.h> | ||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | #include "util.h" | ||
| 8 | |||
| 9 | /* --8<-- hash_type */ | ||
| 10 | typedef int T; | ||
| 11 | |||
| 12 | struct hash_item { | ||
| 13 | struct hash_item *next; | ||
| 14 | char * key; | ||
| 15 | T data; | ||
| 16 | }; | ||
| 17 | |||
| 18 | struct hash_tab { | ||
| 19 | struct hash_item *table[251]; // fit for your needs... | ||
| 20 | }; | ||
| 21 | /* -->8-- */ | ||
| 22 | |||
| 23 | /* --8<-- hash_key */ | ||
| 24 | static unsigned long | ||
| 25 | hash_key(const unsigned char *str) | ||
| 26 | { | ||
| 27 | unsigned long hash = 5381; | ||
| 28 | unsigned int c; | ||
| 29 | |||
| 30 | while ( (c = *str++) != '\0' ) | ||
| 31 | hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ | ||
| 32 | |||
| 33 | return hash; | ||
| 34 | } | ||
| 35 | /* -->8-- */ | ||
| 36 | |||
| 37 | /* --8<-- hash_init */ | ||
| 38 | void | ||
| 39 | hash_init(struct hash_tab *ht) | ||
| 40 | { | ||
| 41 | for ( size_t i = 0; i != NELEM(ht->table); ++i ) | ||
| 42 | ht->table[i] = NULL; | ||
| 43 | } | ||
| 44 | /* -->8-- */ | ||
| 45 | |||
| 46 | /* --8<-- hash_add */ | ||
| 47 | static struct hash_item * | ||
| 48 | hash_add(struct hash_item *next, const char *key, T data) | ||
| 49 | { | ||
| 50 | struct hash_item *new_item; | ||
| 51 | char * new_key; | ||
| 52 | |||
| 53 | new_key = strdup(key); // strdup: not standard but commonly used... | ||
| 54 | new_item = malloc(sizeof *new_item); | ||
| 55 | |||
| 56 | if ( new_key == NULL || new_item == NULL ) { | ||
| 57 | free(new_key); | ||
| 58 | free(new_item); | ||
| 59 | ERROR("out of memory"); | ||
| 60 | return NULL; | ||
| 61 | } | ||
| 62 | |||
| 63 | new_item->next = next; | ||
| 64 | new_item->key = new_key; | ||
| 65 | new_item->data = data; | ||
| 66 | |||
| 67 | return new_item; | ||
| 68 | } | ||
| 69 | /* -->8-- */ | ||
| 70 | |||
| 71 | /* --8<-- hash_lookup */ | ||
| 72 | T * | ||
| 73 | hash_lookup(struct hash_tab *ht, const char *key, T data, int create) | ||
| 74 | { | ||
| 75 | unsigned long h; | ||
| 76 | struct hash_item *item; | ||
| 77 | |||
| 78 | h = hash_key((const unsigned char *) key) % NELEM(ht->table); | ||
| 79 | for ( item = ht->table[h]; item; item = item->next ) | ||
| 80 | if ( strcmp(key, item->key) == 0 ) | ||
| 81 | return &item->data; | ||
| 82 | |||
| 83 | // not found! create? | ||
| 84 | if ( create ) { | ||
| 85 | item = hash_add(ht->table[h], key, data); | ||
| 86 | if ( item ) | ||
| 87 | ht->table[h] = item; | ||
| 88 | else | ||
| 89 | ERROR("can't create item"); | ||
| 90 | } | ||
| 91 | |||
| 92 | return item ? &item->data : NULL; | ||
| 93 | } | ||
| 94 | /* -->8-- */ | ||
| 95 | |||
| 96 | /* --8<-- hash_delete */ | ||
| 97 | bool | ||
| 98 | hash_delete(struct hash_tab *ht, const char *key) | ||
| 99 | { | ||
| 100 | unsigned long h; | ||
| 101 | struct hash_item *prev, *p; | ||
| 102 | |||
| 103 | h = hash_key((const unsigned char *) key) % NELEM(ht->table); | ||
| 104 | prev = NULL; | ||
| 105 | for ( p = ht->table[h]; p; p = p->next ) { | ||
| 106 | if ( strcmp(key, p->key) == 0 ) { | ||
| 107 | if ( prev == NULL ) | ||
| 108 | ht->table[h] = p->next; | ||
| 109 | else | ||
| 110 | prev->next = p->next; | ||
| 111 | |||
| 112 | free(p->key); | ||
| 113 | free(p); | ||
| 114 | |||
| 115 | return true; // successfully removed! | ||
| 116 | } | ||
| 117 | prev = p; | ||
| 118 | } | ||
| 119 | |||
| 120 | return false; | ||
| 121 | } | ||
| 122 | /* -->8-- */ | ||
| 123 | |||
| 124 | /* --8<-- hash_apply */ | ||
| 125 | void | ||
| 126 | hash_apply(struct hash_tab *ht, void (*visit)(const char *key, T data, void *cl), void *cl) | ||
| 127 | { | ||
| 128 | struct hash_item *item; | ||
| 129 | |||
| 130 | for ( size_t i = 0; i != NELEM(ht->table); ++i ) | ||
| 131 | for ( item = ht->table[i]; item; item = item->next ) | ||
| 132 | visit(item->key, item->data, cl); | ||
| 133 | } | ||
| 134 | /* -->8-- */ | ||
| 135 | |||
| 136 | /* --8<-- hash_free */ | ||
| 137 | void | ||
| 138 | hash_free(struct hash_tab *ht) | ||
| 139 | { | ||
| 140 | struct hash_item *p, *next; | ||
| 141 | |||
| 142 | for ( size_t i = 0; i != NELEM(ht->table); ++i ) { | ||
| 143 | for ( p = ht->table[i]; p; p = next ) { | ||
| 144 | next = p->next; | ||
| 145 | free(p->key); | ||
| 146 | free(p); | ||
| 147 | } | ||
| 148 | ht->table[i] = NULL; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | /* -->8-- */ | ||
| 152 | |||
| 153 | static int | ||
| 154 | getword(FILE *fp, char *buf, size_t size, int first(int), int rest(int)) | ||
| 155 | { | ||
| 156 | size_t i = 0; | ||
| 157 | int c; | ||
| 158 | |||
| 159 | c = getc(fp); | ||
| 160 | for ( ; c != EOF; c = getc(fp) ) | ||
| 161 | if ( first(c) ) { | ||
| 162 | if ( i < size - 1 ) | ||
| 163 | buf[i++] = c; | ||
| 164 | c = getc(fp); | ||
| 165 | break; | ||
| 166 | } | ||
| 167 | |||
| 168 | for ( ; c != EOF && rest(c); c = getc(fp) ) | ||
| 169 | if ( i < size - 1 ) | ||
| 170 | buf[i++] = c; | ||
| 171 | |||
| 172 | if ( i < size ) | ||
| 173 | buf[i] = 0; | ||
| 174 | else | ||
| 175 | buf[size - 1] = 0; | ||
| 176 | |||
| 177 | if ( c != EOF ) | ||
| 178 | ungetc(c, fp); | ||
| 179 | |||
| 180 | return c > 0; | ||
| 181 | } | ||
| 182 | |||
| 183 | static int | ||
| 184 | first(int c) | ||
| 185 | { | ||
| 186 | return isalpha(c); | ||
| 187 | } | ||
| 188 | |||
| 189 | static int | ||
| 190 | rest(int c) | ||
| 191 | { | ||
| 192 | return isalpha(c) || c == '_'; | ||
| 193 | } | ||
| 194 | |||
| 195 | static void | ||
| 196 | print(const char *key, T data, void *cl) | ||
| 197 | { | ||
| 198 | fprintf(cl, "%s: %d\n", key, data); | ||
| 199 | } | ||
| 200 | |||
| 201 | int | ||
| 202 | main() | ||
| 203 | { | ||
| 204 | struct hash_tab ht[1]; | ||
| 205 | char word[100]; | ||
| 206 | |||
| 207 | hash_init(ht); | ||
| 208 | |||
| 209 | while ( getword(stdin, word, sizeof word, first, rest) ) { | ||
| 210 | T *p = hash_lookup(ht, word, 0, 1); | ||
| 211 | if ( p ) | ||
| 212 | ++(*p); | ||
| 213 | } | ||
| 214 | |||
| 215 | hash_delete(ht, "new_item"); | ||
| 216 | |||
| 217 | hash_apply(ht, print, stdout); | ||
| 218 | |||
| 219 | hash_free(ht); | ||
| 220 | } | ||
diff --git a/src/heap.c b/src/heap.c new file mode 100644 index 0000000..091e761 --- /dev/null +++ b/src/heap.c | |||
| @@ -0,0 +1,291 @@ | |||
| 1 | #include <assert.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <stdlib.h> | ||
| 5 | #include <time.h> | ||
| 6 | |||
| 7 | #include "util.h" | ||
| 8 | |||
| 9 | typedef int T; | ||
| 10 | |||
| 11 | // https://stackoverflow.com/a/22900767 | ||
| 12 | |||
| 13 | #define LEFT(idx) (idx * 2 + 1) | ||
| 14 | #define RIGHT(idx) (idx * 2 + 2) | ||
| 15 | #define PARENT(idx) ((idx - 1) / 2) | ||
| 16 | |||
| 17 | static void | ||
| 18 | swap(T heap[], size_t i, size_t j) | ||
| 19 | { | ||
| 20 | T temp = heap[i]; | ||
| 21 | heap[i] = heap[j]; | ||
| 22 | heap[j] = temp; | ||
| 23 | } | ||
| 24 | |||
| 25 | #define MAX_HEAP 1 | ||
| 26 | |||
| 27 | #if defined(MAX_HEAP) | ||
| 28 | // MAX-HEAP Implementation | ||
| 29 | static void | ||
| 30 | fixup(T heap[], size_t i) | ||
| 31 | { | ||
| 32 | size_t p = PARENT(i); | ||
| 33 | |||
| 34 | while ( i > 0 && heap[p] < heap[i] ) { | ||
| 35 | swap(heap, p, i); | ||
| 36 | |||
| 37 | i = p; | ||
| 38 | p = PARENT(i); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | static void | ||
| 43 | fixdown(T heap[], size_t i, size_t n) | ||
| 44 | { | ||
| 45 | for ( ;; ) { | ||
| 46 | const size_t l = LEFT(i); | ||
| 47 | const size_t r = RIGHT(i); | ||
| 48 | size_t m = i; | ||
| 49 | |||
| 50 | if ( l < n && heap[m] < heap[l] ) { | ||
| 51 | m = l; | ||
| 52 | } | ||
| 53 | |||
| 54 | if ( r < n && heap[m] < heap[r] ) { | ||
| 55 | m = r; | ||
| 56 | } | ||
| 57 | |||
| 58 | if ( m == i ) { | ||
| 59 | break; | ||
| 60 | } | ||
| 61 | |||
| 62 | swap(heap, m, i); | ||
| 63 | |||
| 64 | i = m; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | static bool | ||
| 69 | is_heap(T heap[], size_t n) | ||
| 70 | { | ||
| 71 | for ( size_t i = 0; i < n / 2; ++i ) { | ||
| 72 | const size_t l = LEFT(i); | ||
| 73 | const size_t r = RIGHT(i); | ||
| 74 | |||
| 75 | if ( l < n && heap[i] < heap[l] ) { | ||
| 76 | return false; | ||
| 77 | } | ||
| 78 | if ( r < n && heap[i] < heap[r] ) { | ||
| 79 | return false; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | return true; | ||
| 83 | } | ||
| 84 | |||
| 85 | #else | ||
| 86 | // MIN-HEAP Implementation | ||
| 87 | static void | ||
| 88 | fixup(T heap[], size_t i) | ||
| 89 | { | ||
| 90 | size_t p = PARENT(i); | ||
| 91 | |||
| 92 | while ( i > 0 && heap[i] < heap[p] ) { | ||
| 93 | swap(heap, i, p); | ||
| 94 | |||
| 95 | i = p; | ||
| 96 | p = PARENT(i); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | static void | ||
| 101 | fixdown(T heap[], size_t i, size_t n) | ||
| 102 | { | ||
| 103 | for ( ;; ) { | ||
| 104 | const size_t l = LEFT(i); | ||
| 105 | const size_t r = RIGHT(i); | ||
| 106 | size_t m = i; | ||
| 107 | |||
| 108 | if ( l < n && heap[l] < heap[m] ) { | ||
| 109 | m = l; | ||
| 110 | } | ||
| 111 | |||
| 112 | if ( r < n && heap[r] < heap[m] ) { | ||
| 113 | m = r; | ||
| 114 | } | ||
| 115 | |||
| 116 | if ( m == i ) { | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | |||
| 120 | swap(heap, m, i); | ||
| 121 | |||
| 122 | i = m; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | static bool | ||
| 127 | is_heap(T heap[], size_t n) | ||
| 128 | { | ||
| 129 | for ( size_t i = 0; i < n / 2; ++i ) { | ||
| 130 | const size_t l = LEFT(i); | ||
| 131 | const size_t r = RIGHT(i); | ||
| 132 | |||
| 133 | if ( l < n && heap[i] > heap[l] ) { | ||
| 134 | return false; | ||
| 135 | } | ||
| 136 | if ( r < n && heap[i] > heap[r] ) { | ||
| 137 | return false; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | return true; | ||
| 141 | } | ||
| 142 | #endif | ||
| 143 | |||
| 144 | static void | ||
| 145 | heapify(T heap[], size_t n) | ||
| 146 | { | ||
| 147 | for ( size_t i = n / 2; i-- > 0; ) { | ||
| 148 | fixdown(heap, i, n); | ||
| 149 | } | ||
| 150 | |||
| 151 | assert(is_heap(heap, n)); | ||
| 152 | } | ||
| 153 | |||
| 154 | static void | ||
| 155 | my_heapsort(T a[], size_t n) | ||
| 156 | { | ||
| 157 | heapify(a, n); | ||
| 158 | |||
| 159 | while ( n-- ) { | ||
| 160 | swap(a, 0, n); | ||
| 161 | fixdown(a, 0, n); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | // ------------------------------------------- | ||
| 166 | |||
| 167 | struct pq { // Priority Queue | ||
| 168 | T heap[251]; | ||
| 169 | size_t sz; | ||
| 170 | }; | ||
| 171 | |||
| 172 | void | ||
| 173 | pq_init(struct pq *pq) | ||
| 174 | { | ||
| 175 | pq->sz = 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | bool | ||
| 179 | pq_push(struct pq *pq, T data) | ||
| 180 | { | ||
| 181 | if ( pq->sz == NELEM(pq->heap) ) { | ||
| 182 | return false; | ||
| 183 | } | ||
| 184 | |||
| 185 | pq->heap[pq->sz] = data; | ||
| 186 | fixup(pq->heap, pq->sz); | ||
| 187 | ++pq->sz; | ||
| 188 | return true; | ||
| 189 | } | ||
| 190 | |||
| 191 | bool | ||
| 192 | pq_pop(struct pq *pq, T *data) | ||
| 193 | { | ||
| 194 | if ( pq->sz == 0 ) { | ||
| 195 | return false; | ||
| 196 | } | ||
| 197 | |||
| 198 | *data = pq->heap[0]; | ||
| 199 | --pq->sz; | ||
| 200 | pq->heap[0] = pq->heap[pq->sz]; | ||
| 201 | fixdown(pq->heap, 0, pq->sz); | ||
| 202 | return true; | ||
| 203 | } | ||
| 204 | |||
| 205 | // ------------------------------------------- | ||
| 206 | |||
| 207 | void | ||
| 208 | print_heap(T heap[], size_t n) | ||
| 209 | { | ||
| 210 | if ( n ) { | ||
| 211 | printf("%d", heap[0]); | ||
| 212 | for ( size_t i = 1; i != n; ++i ) { | ||
| 213 | printf(", %d", heap[i]); | ||
| 214 | } | ||
| 215 | putchar('\n'); | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | void | ||
| 220 | test_heapsort(void) | ||
| 221 | { | ||
| 222 | static const size_t N = 1000000; | ||
| 223 | T array[N]; | ||
| 224 | |||
| 225 | puts("fülle...."); | ||
| 226 | srand(time(NULL)); | ||
| 227 | for ( size_t idx = 0; idx != NELEM(array); ++idx ) { | ||
| 228 | array[idx] = rand(); | ||
| 229 | } | ||
| 230 | |||
| 231 | puts("sortiere...."); | ||
| 232 | clock_t start = clock(); | ||
| 233 | my_heapsort(array, NELEM(array)); | ||
| 234 | clock_t end = clock(); | ||
| 235 | |||
| 236 | puts("teste..."); | ||
| 237 | for ( size_t idx = 1; idx != NELEM(array); ++idx ) { | ||
| 238 | #if defined(MAX_HEAP) | ||
| 239 | if ( array[idx - 1] > array[idx] ) { | ||
| 240 | fprintf(stderr, "Fehler an Pos: %zu\n", idx); | ||
| 241 | exit(EXIT_FAILURE); | ||
| 242 | } | ||
| 243 | #else | ||
| 244 | if ( array[idx - 1] < array[idx] ) { | ||
| 245 | fprintf(stderr, "Fehler an Pos: %zu\n", idx); | ||
| 246 | exit(EXIT_FAILURE); | ||
| 247 | } | ||
| 248 | #endif | ||
| 249 | } | ||
| 250 | printf("ok! (%.3lf sec)\n", ((double) end - start) / CLOCKS_PER_SEC); | ||
| 251 | } | ||
| 252 | |||
| 253 | void | ||
| 254 | test_pq(void) | ||
| 255 | { | ||
| 256 | struct pq pq[1]; | ||
| 257 | |||
| 258 | pq_init(pq); | ||
| 259 | |||
| 260 | for ( int i = 0; i != 10; ++i ) { | ||
| 261 | pq_push(pq, rand()); | ||
| 262 | } | ||
| 263 | |||
| 264 | T data; | ||
| 265 | while ( pq_pop(pq, &data) ) { | ||
| 266 | printf("%d\n", data); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | int | ||
| 271 | main(void) | ||
| 272 | { | ||
| 273 | test_heapsort(); | ||
| 274 | test_pq(); | ||
| 275 | #if 1 // Heap-Testprogramm | ||
| 276 | // Beispiel aus "Informatik - Datenstrukturen und Konzepte der Abstraktion" | ||
| 277 | // Kapitel 5.10, Seite 372 ff. | ||
| 278 | T heap[20] = { 18, 18, 16, 9, 7, 1, 9, 3, 7, 5 }; | ||
| 279 | |||
| 280 | //heapify(heap, 10); | ||
| 281 | assert(is_heap(heap, 10)); | ||
| 282 | print_heap(heap, 10); | ||
| 283 | |||
| 284 | //heap[10] = 13; fixup(heap, 10); | ||
| 285 | swap(heap, 0, 9); | ||
| 286 | fixdown(heap, 0, 9); | ||
| 287 | |||
| 288 | assert(is_heap(heap, 9)); | ||
| 289 | print_heap(heap, 9); | ||
| 290 | #endif | ||
| 291 | } | ||
diff --git a/src/insertsort.c b/src/insertsort.c new file mode 100644 index 0000000..1a30a1a --- /dev/null +++ b/src/insertsort.c | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <time.h> | ||
| 4 | |||
| 5 | #include "util.h" | ||
| 6 | |||
| 7 | typedef int T; | ||
| 8 | |||
| 9 | void | ||
| 10 | insertsort(T a[], size_t n) | ||
| 11 | { | ||
| 12 | for ( size_t i = 1; i < n; ++i ) { | ||
| 13 | size_t j = i; | ||
| 14 | const T value = a[i]; | ||
| 15 | |||
| 16 | for ( ; j > 0 && a[j - 1] > value; --j ) | ||
| 17 | a[j] = a[j - 1]; | ||
| 18 | |||
| 19 | a[j] = value; | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | int | ||
| 24 | main(void) | ||
| 25 | { | ||
| 26 | T a[10]; | ||
| 27 | |||
| 28 | srand(time(NULL)); | ||
| 29 | for ( size_t i = 0; i != NELEM(a); ++i ) | ||
| 30 | a[i] = rand() % 100; | ||
| 31 | |||
| 32 | insertsort(a, NELEM(a)); | ||
| 33 | |||
| 34 | for ( size_t i = 0; i != NELEM(a); ++i ) | ||
| 35 | printf("%d ", a[i]); | ||
| 36 | putchar('\n'); | ||
| 37 | return EXIT_SUCCESS; | ||
| 38 | } | ||
diff --git a/src/list-tail-node.c b/src/list-tail-node.c new file mode 100644 index 0000000..edfcf31 --- /dev/null +++ b/src/list-tail-node.c | |||
| @@ -0,0 +1,197 @@ | |||
| 1 | /* Standard C */ | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <stdlib.h> | ||
| 5 | |||
| 6 | /* Project */ | ||
| 7 | #include "util.h" | ||
| 8 | |||
| 9 | /* --8<-- list_tail_type */ | ||
| 10 | typedef int T; | ||
| 11 | |||
| 12 | struct list_node { | ||
| 13 | struct list_node *next; | ||
| 14 | T data; | ||
| 15 | }; | ||
| 16 | |||
| 17 | struct list { | ||
| 18 | struct list_node *head, *tail; | ||
| 19 | }; | ||
| 20 | /* -->8-- */ | ||
| 21 | |||
| 22 | /* --8<-- list_tail_init */ | ||
| 23 | void | ||
| 24 | list_init(struct list *list) | ||
| 25 | { | ||
| 26 | list->head = NULL; | ||
| 27 | } | ||
| 28 | /* -->8-- */ | ||
| 29 | |||
| 30 | /* --8<-- list_tail_create_node */ | ||
| 31 | static struct list_node * | ||
| 32 | create_node(struct list_node *next, T data) | ||
| 33 | { | ||
| 34 | struct list_node *node = malloc(sizeof *node); | ||
| 35 | |||
| 36 | if ( node ) { | ||
| 37 | node->next = next; | ||
| 38 | node->data = data; | ||
| 39 | } | ||
| 40 | return node; | ||
| 41 | } | ||
| 42 | /* -->8-- */ | ||
| 43 | |||
| 44 | /* --8<-- list_tail_push_back */ | ||
| 45 | void | ||
| 46 | list_push_back(struct list *list, T data) | ||
| 47 | { | ||
| 48 | struct list_node *node = create_node(NULL, data); | ||
| 49 | |||
| 50 | if ( node ) { | ||
| 51 | if ( list->head == NULL ) { | ||
| 52 | list->head = node; | ||
| 53 | } | ||
| 54 | else { | ||
| 55 | list->tail->next = node; | ||
| 56 | } | ||
| 57 | list->tail = node; | ||
| 58 | } | ||
| 59 | else { | ||
| 60 | ERROR("out of memory"); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | /* -->8-- */ | ||
| 64 | |||
| 65 | /* --8<-- list_tail_front */ | ||
| 66 | void | ||
| 67 | list_push_front(struct list *list, T data) | ||
| 68 | { | ||
| 69 | struct list_node *node = create_node(list->head, data); | ||
| 70 | |||
| 71 | if ( node ) { | ||
| 72 | if ( list->head == NULL ) { // Einfügen in eine leere Liste? | ||
| 73 | list->tail = node; | ||
| 74 | } | ||
| 75 | list->head = node; | ||
| 76 | } | ||
| 77 | else { | ||
| 78 | ERROR("out of memory"); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | /* -->8-- */ | ||
| 82 | |||
| 83 | /* --8<-- list_tail_pop_front */ | ||
| 84 | bool | ||
| 85 | list_pop_front(struct list *list, T *data) | ||
| 86 | { | ||
| 87 | if ( list->head ) { | ||
| 88 | struct list_node *next = list->head->next; | ||
| 89 | |||
| 90 | if ( data ) { | ||
| 91 | *data = list->head->data; | ||
| 92 | } | ||
| 93 | free(list->head); | ||
| 94 | list->head = next; | ||
| 95 | |||
| 96 | return true; | ||
| 97 | } | ||
| 98 | else { | ||
| 99 | return false; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | /* -->8-- */ | ||
| 103 | |||
| 104 | /* --8<-- list_tail_insert_next */ | ||
| 105 | void | ||
| 106 | list_insert_next(struct list *list, struct list_node *node, T data) | ||
| 107 | { | ||
| 108 | if ( node == NULL ) { // Am Anfang einfügen | ||
| 109 | list_push_front(list, data); | ||
| 110 | } | ||
| 111 | else { | ||
| 112 | struct list_node *new_node = create_node(node->next, data); | ||
| 113 | |||
| 114 | if ( new_node ) { | ||
| 115 | if ( node->next == NULL ) { // Am Ende einfügen | ||
| 116 | list->tail = new_node; | ||
| 117 | } | ||
| 118 | node->next = new_node; | ||
| 119 | } | ||
| 120 | else { | ||
| 121 | ERROR("out of memory"); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | /* -->8-- */ | ||
| 126 | |||
| 127 | /* --8<-- list_tail_delete_next */ | ||
| 128 | void | ||
| 129 | list_delete_next(struct list *list, struct list_node *node, T *data) | ||
| 130 | { | ||
| 131 | if ( node == NULL ) { // Am Anfang entfernen | ||
| 132 | list_pop_front(list, data); | ||
| 133 | } | ||
| 134 | else { | ||
| 135 | if ( node->next ) { | ||
| 136 | struct list_node *old_node = node->next; | ||
| 137 | node->next = node->next->next; | ||
| 138 | |||
| 139 | if ( node->next == NULL ) { | ||
| 140 | list->tail = node; | ||
| 141 | } | ||
| 142 | |||
| 143 | if ( data ) { | ||
| 144 | *data = old_node->data; | ||
| 145 | } | ||
| 146 | free(old_node); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | /* -->8-- */ | ||
| 151 | |||
| 152 | /* --8<-- list_tail_empty */ | ||
| 153 | bool | ||
| 154 | list_empty(struct list *list) | ||
| 155 | { | ||
| 156 | return list->head == NULL; | ||
| 157 | } | ||
| 158 | /* -->8-- */ | ||
| 159 | |||
| 160 | /* --8<-- list_tail_free */ | ||
| 161 | void | ||
| 162 | list_free(struct list *list) | ||
| 163 | { | ||
| 164 | struct list_node *item, *next; | ||
| 165 | |||
| 166 | for ( item = list->head; item; item = next ) { | ||
| 167 | next = item->next; | ||
| 168 | free(item); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | /* -->8-- */ | ||
| 172 | |||
| 173 | int | ||
| 174 | main() | ||
| 175 | { | ||
| 176 | struct list list[1]; | ||
| 177 | |||
| 178 | list_init(list); | ||
| 179 | |||
| 180 | for ( int i = 0; i != 10; ++i ) | ||
| 181 | list_push_front(list, -i); | ||
| 182 | |||
| 183 | for ( int i = 0; i != 10; ++i ) | ||
| 184 | list_push_back(list, i); | ||
| 185 | |||
| 186 | while ( !list_empty(list) ) { | ||
| 187 | int i; | ||
| 188 | if ( list_pop_front(list, &i) ) | ||
| 189 | printf("%d\n", i); | ||
| 190 | else | ||
| 191 | ERROR("this shouldn't happen!"); | ||
| 192 | } | ||
| 193 | |||
| 194 | list_free(list); | ||
| 195 | |||
| 196 | return EXIT_SUCCESS; | ||
| 197 | } | ||
diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..d18dae4 --- /dev/null +++ b/src/list.c | |||
| @@ -0,0 +1,264 @@ | |||
| 1 | /* simple Implementation of single linked lists */ | ||
| 2 | /* written and placed in the public domain by Thomas Schmucker */ | ||
| 3 | |||
| 4 | /* Standard C */ | ||
| 5 | #include <stdio.h> | ||
| 6 | #include <stdlib.h> | ||
| 7 | #include <time.h> | ||
| 8 | |||
| 9 | /* Project */ | ||
| 10 | #include "util.h" | ||
| 11 | |||
| 12 | /* --8<-- list_type */ | ||
| 13 | typedef int T; | ||
| 14 | |||
| 15 | struct list_item { | ||
| 16 | struct list_item *next; | ||
| 17 | T data; | ||
| 18 | }; | ||
| 19 | /* -->8-- */ | ||
| 20 | |||
| 21 | /* --8<-- list_add */ | ||
| 22 | struct list_item * | ||
| 23 | list_add(struct list_item *next, T data) | ||
| 24 | { | ||
| 25 | struct list_item *new_item; | ||
| 26 | |||
| 27 | new_item = malloc(sizeof *new_item); | ||
| 28 | if ( new_item ) { | ||
| 29 | new_item->data = data; | ||
| 30 | new_item->next = next; | ||
| 31 | } | ||
| 32 | else { | ||
| 33 | ERROR("out of memory"); | ||
| 34 | } | ||
| 35 | |||
| 36 | return new_item; | ||
| 37 | } | ||
| 38 | /* -->8-- */ | ||
| 39 | |||
| 40 | /* --8<-- list_insert_next */ | ||
| 41 | void | ||
| 42 | list_insert_next(struct list_item *list, T data) | ||
| 43 | { | ||
| 44 | struct list_item *new_item; | ||
| 45 | |||
| 46 | new_item = list_add(list->next, data); | ||
| 47 | if ( new_item ) { | ||
| 48 | list->next = new_item; | ||
| 49 | } | ||
| 50 | else { | ||
| 51 | ERROR("out of memory"); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | /* -->8-- */ | ||
| 55 | |||
| 56 | /* --8<-- list_delete */ | ||
| 57 | struct list_item * | ||
| 58 | list_delete(struct list_item *list, T data) | ||
| 59 | { | ||
| 60 | struct list_item *prev = NULL; | ||
| 61 | |||
| 62 | for ( struct list_item *p = list; p; p = p->next ) { | ||
| 63 | if ( p->data == data ) { | ||
| 64 | if ( prev == NULL ) { /* first element in list? */ | ||
| 65 | list = p->next; | ||
| 66 | } | ||
| 67 | else { | ||
| 68 | prev->next = p->next; | ||
| 69 | } | ||
| 70 | |||
| 71 | free(p); | ||
| 72 | |||
| 73 | return list; | ||
| 74 | } | ||
| 75 | prev = p; | ||
| 76 | } | ||
| 77 | #ifdef LIST_REPORT_ERROR | ||
| 78 | ERROR("data not found"); | ||
| 79 | #endif | ||
| 80 | return list; | ||
| 81 | } | ||
| 82 | /* -->8-- */ | ||
| 83 | |||
| 84 | /* --8<-- list_delete_next */ | ||
| 85 | void | ||
| 86 | list_delete_next(struct list_item *list) | ||
| 87 | { | ||
| 88 | if ( list->next ) { | ||
| 89 | struct list_item *temp = list->next; | ||
| 90 | |||
| 91 | list->next = list->next->next; | ||
| 92 | |||
| 93 | free(temp); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | /* -->8-- */ | ||
| 97 | |||
| 98 | /* --8<-- list_length */ | ||
| 99 | size_t | ||
| 100 | list_length(struct list_item *list) | ||
| 101 | { | ||
| 102 | size_t len = 0; | ||
| 103 | |||
| 104 | for ( ; list; list = list->next ) { | ||
| 105 | ++len; | ||
| 106 | } | ||
| 107 | |||
| 108 | return len; | ||
| 109 | } | ||
| 110 | /* -->8-- */ | ||
| 111 | |||
| 112 | /* --8<-- list_copy */ | ||
| 113 | struct list_item * | ||
| 114 | list_copy(struct list_item *list) | ||
| 115 | { | ||
| 116 | struct list_item *head = NULL, **p = &head; | ||
| 117 | |||
| 118 | for ( ; list; list = list->next ) { | ||
| 119 | *p = malloc(sizeof **p); | ||
| 120 | if ( *p ) { | ||
| 121 | (*p)->data = list->data; // copy elements | ||
| 122 | p = &(*p)->next; | ||
| 123 | } | ||
| 124 | else { | ||
| 125 | ERROR("out of memory"); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | *p = NULL; | ||
| 129 | return head; | ||
| 130 | } | ||
| 131 | /* -->8-- */ | ||
| 132 | |||
| 133 | /* --8<-- list_reverse */ | ||
| 134 | struct list_item * | ||
| 135 | list_reverse(struct list_item *list) | ||
| 136 | { | ||
| 137 | struct list_item *head = NULL, *next; | ||
| 138 | |||
| 139 | for ( ; list; list = next ) { | ||
| 140 | next = list->next; | ||
| 141 | list->next = head; | ||
| 142 | head = list; | ||
| 143 | } | ||
| 144 | return head; | ||
| 145 | } | ||
| 146 | /* -->8-- */ | ||
| 147 | |||
| 148 | /* --8<-- list_apply */ | ||
| 149 | void | ||
| 150 | list_apply(struct list_item *list, void (*visit)(T data, void *cl), void *cl) | ||
| 151 | { | ||
| 152 | for ( ; list; list = list->next ) { | ||
| 153 | visit(list->data, cl); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | /* -->8-- */ | ||
| 157 | |||
| 158 | /* --8<-- list_merge */ | ||
| 159 | struct list_item * | ||
| 160 | list_merge(struct list_item *a, struct list_item *b) | ||
| 161 | { | ||
| 162 | struct list_item dummy = { .next = NULL }; | ||
| 163 | struct list_item *head = &dummy, *c = head; | ||
| 164 | |||
| 165 | while ( a && b ) | ||
| 166 | if ( a->data < b->data ) { | ||
| 167 | c->next = a, c = a, a = a->next; | ||
| 168 | } | ||
| 169 | else { | ||
| 170 | c->next = b, c = b, b = b->next; | ||
| 171 | } | ||
| 172 | |||
| 173 | c->next = a ? a : b; | ||
| 174 | |||
| 175 | return head->next; | ||
| 176 | } | ||
| 177 | /* -->8-- */ | ||
| 178 | |||
| 179 | /* --8<-- list_sort */ | ||
| 180 | struct list_item * | ||
| 181 | list_sort(struct list_item *c) | ||
| 182 | { | ||
| 183 | if ( c == NULL || c->next == NULL ) | ||
| 184 | return c; | ||
| 185 | |||
| 186 | struct list_item *a = c, | ||
| 187 | *b = c->next; | ||
| 188 | |||
| 189 | while ( b && b->next ) { | ||
| 190 | c = c->next, b = b->next->next; | ||
| 191 | } | ||
| 192 | |||
| 193 | b = c->next, c->next = NULL; | ||
| 194 | |||
| 195 | return list_merge(list_sort(a), list_sort(b)); | ||
| 196 | } | ||
| 197 | /* -->8-- */ | ||
| 198 | |||
| 199 | /* --8<-- list_free */ | ||
| 200 | void | ||
| 201 | list_free(struct list_item *list) | ||
| 202 | { | ||
| 203 | struct list_item *next; | ||
| 204 | |||
| 205 | for ( ; list; list = next ) { | ||
| 206 | next = list->next; | ||
| 207 | free(list); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | /* -->8-- */ | ||
| 211 | |||
| 212 | /* --8<-- list_apply_sample */ | ||
| 213 | static void | ||
| 214 | print_data(T data, void *cl) | ||
| 215 | { | ||
| 216 | fprintf(cl, "%d\n", data); | ||
| 217 | } | ||
| 218 | /* -->8-- */ | ||
| 219 | |||
| 220 | int | ||
| 221 | main() | ||
| 222 | { | ||
| 223 | clock_t start; | ||
| 224 | |||
| 225 | /* | ||
| 226 | struct list_item *mylist = NULL; | ||
| 227 | |||
| 228 | mylist = list_add(mylist, 42); | ||
| 229 | mylist = list_add(mylist, 43); | ||
| 230 | mylist = list_add(mylist, 44); | ||
| 231 | |||
| 232 | mylist = list_delete(mylist, 45); | ||
| 233 | |||
| 234 | list_apply(mylist, print_data, stdout); | ||
| 235 | |||
| 236 | struct list_item *mylist2 = list_reverse(list_copy(mylist)); | ||
| 237 | |||
| 238 | list_free(mylist); | ||
| 239 | list_apply(mylist2, print_data); | ||
| 240 | list_free(mylist2); | ||
| 241 | */ | ||
| 242 | |||
| 243 | srand(time(NULL)); | ||
| 244 | |||
| 245 | static const int COUNT = 10000000; | ||
| 246 | |||
| 247 | struct list_item *x = NULL; | ||
| 248 | for ( int i = 0; i != COUNT; ++i ) { | ||
| 249 | int r = rand(); | ||
| 250 | x = list_add(x, r); | ||
| 251 | } | ||
| 252 | |||
| 253 | puts("start"); | ||
| 254 | start = clock(); | ||
| 255 | x = list_sort(x); | ||
| 256 | printf("Fertig: %.3lf sec\n", (double) (clock() - start) / CLOCKS_PER_SEC); | ||
| 257 | |||
| 258 | //list_apply(x, print_data); | ||
| 259 | printf("Len: %zu\n", list_length(x)); | ||
| 260 | |||
| 261 | list_free(x); | ||
| 262 | |||
| 263 | return EXIT_SUCCESS; | ||
| 264 | } | ||
diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 0000000..6a472ee --- /dev/null +++ b/src/queue.c | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | /* Standard C */ | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <stdlib.h> | ||
| 5 | |||
| 6 | /* Project */ | ||
| 7 | #include "util.h" | ||
| 8 | |||
| 9 | /* --8<-- queue_type */ | ||
| 10 | typedef int T; | ||
| 11 | |||
| 12 | struct queue_item { | ||
| 13 | struct queue_item *next; | ||
| 14 | T data; | ||
| 15 | }; | ||
| 16 | |||
| 17 | struct queue { | ||
| 18 | struct queue_item *head, *tail; | ||
| 19 | }; | ||
| 20 | /* -->8-- */ | ||
| 21 | |||
| 22 | /* --8<-- queue_init */ | ||
| 23 | void | ||
| 24 | queue_init(struct queue *queue) | ||
| 25 | { | ||
| 26 | queue->head = NULL; | ||
| 27 | } | ||
| 28 | /* -->8-- */ | ||
| 29 | |||
| 30 | /* --8<-- queue_put */ | ||
| 31 | void | ||
| 32 | queue_put(struct queue *queue, T data) | ||
| 33 | { | ||
| 34 | struct queue_item *new_item; | ||
| 35 | |||
| 36 | if ( (new_item = malloc(sizeof *new_item)) != NULL ) { | ||
| 37 | struct queue_item *tmp = queue->tail; | ||
| 38 | new_item->data = data; | ||
| 39 | new_item->next = NULL; | ||
| 40 | queue->tail = new_item; | ||
| 41 | if ( queue->head == NULL ) | ||
| 42 | queue->head = queue->tail; | ||
| 43 | else | ||
| 44 | tmp->next = queue->tail; | ||
| 45 | } | ||
| 46 | else { | ||
| 47 | ERROR("out of memory"); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | /* -->8-- */ | ||
| 51 | |||
| 52 | /* --8<-- queue_get */ | ||
| 53 | bool | ||
| 54 | queue_get(struct queue *queue, T *data) | ||
| 55 | { | ||
| 56 | if ( queue->head ) { | ||
| 57 | struct queue_item *next = queue->head->next; | ||
| 58 | |||
| 59 | if ( data ) { | ||
| 60 | *data = queue->head->data; | ||
| 61 | } | ||
| 62 | free(queue->head); | ||
| 63 | queue->head = next; | ||
| 64 | |||
| 65 | return true; | ||
| 66 | } | ||
| 67 | else | ||
| 68 | return false; | ||
| 69 | } | ||
| 70 | /* -->8-- */ | ||
| 71 | |||
| 72 | /* --8<-- queue_empty */ | ||
| 73 | bool | ||
| 74 | queue_empty(struct queue *queue) | ||
| 75 | { | ||
| 76 | return queue->head == NULL; | ||
| 77 | } | ||
| 78 | /* -->8-- */ | ||
| 79 | |||
| 80 | /* --8<-- queue_free */ | ||
| 81 | void | ||
| 82 | queue_free(struct queue *queue) | ||
| 83 | { | ||
| 84 | struct queue_item *item, *next; | ||
| 85 | |||
| 86 | for ( item = queue->head; item; item = next ) { | ||
| 87 | next = item->next; | ||
| 88 | free(item); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | /* -->8-- */ | ||
| 92 | |||
| 93 | int | ||
| 94 | main() | ||
| 95 | { | ||
| 96 | struct queue queue[1]; | ||
| 97 | |||
| 98 | queue_init(queue); | ||
| 99 | |||
| 100 | for ( int i = 0; i != 10; ++i ) { | ||
| 101 | queue_put(queue, i); | ||
| 102 | } | ||
| 103 | |||
| 104 | while ( !queue_empty(queue) ) { | ||
| 105 | int i; | ||
| 106 | if ( queue_get(queue, &i) ) | ||
| 107 | printf("%d\n", i); | ||
| 108 | else | ||
| 109 | ERROR("this shouldn't happen!"); | ||
| 110 | } | ||
| 111 | |||
| 112 | queue_free(queue); | ||
| 113 | |||
| 114 | return EXIT_SUCCESS; | ||
| 115 | } | ||
diff --git a/src/quicksort.c b/src/quicksort.c new file mode 100644 index 0000000..4657dcd --- /dev/null +++ b/src/quicksort.c | |||
| @@ -0,0 +1,684 @@ | |||
| 1 | #include <assert.h> | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | #include <time.h> | ||
| 5 | |||
| 6 | #include "util.h" | ||
| 7 | |||
| 8 | static int | ||
| 9 | bigrand(void) | ||
| 10 | { | ||
| 11 | int x = (rand() << 24) | (rand() << 16) | (rand() << 8) | rand(); | ||
| 12 | if ( x < 0 ) | ||
| 13 | return -x; | ||
| 14 | return x; | ||
| 15 | } | ||
| 16 | |||
| 17 | static int | ||
| 18 | randint(int l, int u) | ||
| 19 | { | ||
| 20 | return l + bigrand() % (u - l + 1); | ||
| 21 | } | ||
| 22 | |||
| 23 | typedef int T; | ||
| 24 | |||
| 25 | static const int CUTOFF = 128; | ||
| 26 | |||
| 27 | static inline void | ||
| 28 | swap(T a[], int i, int j) | ||
| 29 | { | ||
| 30 | T t = a[i]; | ||
| 31 | a[i] = a[j]; | ||
| 32 | a[j] = t; | ||
| 33 | } | ||
| 34 | |||
| 35 | static void | ||
| 36 | insertsort(T a[], int n) | ||
| 37 | { | ||
| 38 | int i, j; | ||
| 39 | for ( i = 1; i < n; ++i ) { | ||
| 40 | T t = a[i]; | ||
| 41 | for ( j = i; j > 0 && a[j - 1] > t; --j ) | ||
| 42 | a[j] = a[j - 1]; | ||
| 43 | a[j] = t; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | static void | ||
| 48 | quicksort(T a[], int n) | ||
| 49 | { | ||
| 50 | int i, last; | ||
| 51 | |||
| 52 | if ( n <= CUTOFF ) | ||
| 53 | return; | ||
| 54 | |||
| 55 | swap(a, 0, bigrand() % n); | ||
| 56 | |||
| 57 | last = 0; | ||
| 58 | for ( i = 1; i < n; ++i ) | ||
| 59 | if ( a[i] < a[0] ) | ||
| 60 | swap(a, ++last, i); | ||
| 61 | |||
| 62 | swap(a, 0, last); | ||
| 63 | |||
| 64 | quicksort(a, last); | ||
| 65 | quicksort(a + last + 1, n - last - 1); | ||
| 66 | } | ||
| 67 | |||
| 68 | void | ||
| 69 | my_quicksort(T a[], int n) | ||
| 70 | { | ||
| 71 | quicksort(a, n); | ||
| 72 | insertsort(a, n); | ||
| 73 | } | ||
| 74 | |||
| 75 | static int | ||
| 76 | cmp(const void *a, const void *b) | ||
| 77 | { | ||
| 78 | const int *pa = (const T *) a; | ||
| 79 | const int *pb = (const T *) b; | ||
| 80 | |||
| 81 | if ( *pa < *pb ) | ||
| 82 | return -1; | ||
| 83 | if ( *pa > *pb ) | ||
| 84 | return 1; | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | void | ||
| 89 | c_quicksort(T a[], int n) | ||
| 90 | { | ||
| 91 | assert(n >= 0); | ||
| 92 | qsort(a, (size_t) n, sizeof(T), cmp); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* This function takes last element as pivot, places | ||
| 96 | the pivot element at its correct position in sorted | ||
| 97 | array, and places all smaller (smaller than pivot) | ||
| 98 | to left of pivot and all greater elements to right | ||
| 99 | of pivot */ | ||
| 100 | int | ||
| 101 | partition(int arr[], int low, int high) | ||
| 102 | { | ||
| 103 | int pivot = arr[high]; // pivot | ||
| 104 | int i = (low - 1); // Index of smaller element | ||
| 105 | |||
| 106 | for ( int j = low; j <= high - 1; j++ ) { | ||
| 107 | // If current element is smaller than or | ||
| 108 | // equal to pivot | ||
| 109 | if ( arr[j] <= pivot ) { | ||
| 110 | i++; // increment index of smaller element | ||
| 111 | swap(arr, i, j); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | swap(arr, i + 1, high); | ||
| 115 | return (i + 1); | ||
| 116 | } | ||
| 117 | |||
| 118 | /* The main function that implements QuickSort | ||
| 119 | arr[] --> Array to be sorted, | ||
| 120 | low --> Starting index, | ||
| 121 | high --> Ending index */ | ||
| 122 | void | ||
| 123 | quickSort(int arr[], int low, int high) | ||
| 124 | { | ||
| 125 | while ( low < high ) { | ||
| 126 | /* pi is partitioning index, arr[p] is now | ||
| 127 | at right place */ | ||
| 128 | int pi = partition(arr, low, high); | ||
| 129 | |||
| 130 | if ( pi - low < high - pi ) { | ||
| 131 | quickSort(arr, low, pi - 1); | ||
| 132 | low = pi + 1; | ||
| 133 | } | ||
| 134 | else { | ||
| 135 | quickSort(arr, pi + 1, high); | ||
| 136 | high = pi - 1; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | void | ||
| 142 | g4g_quicksort(T a[], int n) | ||
| 143 | { | ||
| 144 | quickSort(a, 0, n - 1); | ||
| 145 | } | ||
| 146 | |||
| 147 | static void | ||
| 148 | three_way_quicksort(int a[], int l, int r) | ||
| 149 | { | ||
| 150 | int k; | ||
| 151 | T v = a[r]; | ||
| 152 | |||
| 153 | if ( r <= l ) | ||
| 154 | return; | ||
| 155 | |||
| 156 | int i = l - 1, j = r, p = l - 1, q = r; | ||
| 157 | |||
| 158 | for ( ;; ) { | ||
| 159 | while ( a[++i] < v ) | ||
| 160 | ; | ||
| 161 | while ( v < a[--j] ) | ||
| 162 | if ( j == l ) | ||
| 163 | break; | ||
| 164 | if ( i >= j ) | ||
| 165 | break; | ||
| 166 | |||
| 167 | swap(a, i, j); | ||
| 168 | |||
| 169 | if ( a[i] == v ) | ||
| 170 | swap(a, ++p, i); | ||
| 171 | if ( v == a[j] ) | ||
| 172 | swap(a, --q, j); | ||
| 173 | } | ||
| 174 | swap(a, i, r); | ||
| 175 | j = i - 1; | ||
| 176 | i = i + 1; | ||
| 177 | |||
| 178 | for ( k = l; k <= p; ++k, --j ) | ||
| 179 | swap(a, k, j); | ||
| 180 | for ( k = r - 1; k >= q; --k, ++i ) | ||
| 181 | swap(a, k, i); | ||
| 182 | |||
| 183 | three_way_quicksort(a, l, j); | ||
| 184 | three_way_quicksort(a, i, r); | ||
| 185 | } | ||
| 186 | |||
| 187 | void | ||
| 188 | sed_quicksort(int a[], int n) | ||
| 189 | { | ||
| 190 | three_way_quicksort(a, 0, n - 1); | ||
| 191 | } | ||
| 192 | |||
| 193 | /* ====================== HEAPSORT ======================= */ | ||
| 194 | |||
| 195 | #define LEFT(idx) (idx * 2 + 1) | ||
| 196 | #define RIGHT(idx) (idx * 2 + 2) | ||
| 197 | #define PARENT(idx) ((idx - 1) / 2) | ||
| 198 | |||
| 199 | static void | ||
| 200 | fixdown(T heap[], int i, int n) | ||
| 201 | { | ||
| 202 | for ( ;; ) { | ||
| 203 | const int l = LEFT(i); | ||
| 204 | const int r = RIGHT(i); | ||
| 205 | int m = i; | ||
| 206 | |||
| 207 | if ( l < n && heap[m] < heap[l] ) | ||
| 208 | m = l; | ||
| 209 | |||
| 210 | if ( r < n && heap[m] < heap[r] ) | ||
| 211 | m = r; | ||
| 212 | |||
| 213 | if ( m == i ) | ||
| 214 | break; | ||
| 215 | |||
| 216 | swap(heap, m, i); | ||
| 217 | |||
| 218 | i = m; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | static void | ||
| 223 | heapify(T heap[], int n) | ||
| 224 | { | ||
| 225 | for ( int i = n / 2 - 1; i >= 0; --i ) | ||
| 226 | fixdown(heap, i, n); | ||
| 227 | } | ||
| 228 | |||
| 229 | void | ||
| 230 | my_heapsort(T a[], int n) | ||
| 231 | { | ||
| 232 | heapify(a, n); | ||
| 233 | |||
| 234 | for ( int i = n - 1; i >= 0; --i ) { | ||
| 235 | swap(a, 0, i); | ||
| 236 | fixdown(a, 0, i); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | void | ||
| 241 | heapsort_bu(T *data, int n) // zu sortierendes Feld und seine Länge | ||
| 242 | { | ||
| 243 | T val; | ||
| 244 | int parent, child; | ||
| 245 | int root = n >> 1; // erstes Blatt im Baum | ||
| 246 | int count = 0; // Zähler für Anzahl der Vergleiche | ||
| 247 | |||
| 248 | for ( ;; ) { | ||
| 249 | if ( root ) { // Teil 1: Konstruktion des Heaps | ||
| 250 | parent = --root; | ||
| 251 | val = data[root]; // zu versickernder Wert | ||
| 252 | } | ||
| 253 | else if ( --n ) { // Teil 2: eigentliche Sortierung | ||
| 254 | val = data[n]; // zu versickernder Wert vom Heap-Ende | ||
| 255 | data[n] = data[0]; // Spitze des Heaps hinter den Heap in | ||
| 256 | parent = 0; // den sortierten Bereich verschieben | ||
| 257 | } | ||
| 258 | else // Heap ist leer; Sortierung beendet | ||
| 259 | break; | ||
| 260 | |||
| 261 | while ( (child = (parent + 1) << 1) < n ) // zweites (!) Kind; | ||
| 262 | { // Abbruch am Ende des Heaps | ||
| 263 | if ( ++count, data[child - 1] > data[child] ) // größeres Kind wählen | ||
| 264 | --child; | ||
| 265 | |||
| 266 | data[parent] = data[child]; // größeres Kind nach oben rücken | ||
| 267 | parent = child; // in der Ebene darunter weitersuchen | ||
| 268 | } | ||
| 269 | |||
| 270 | if ( child == n ) // ein einzelnes Kind am Heap-Ende | ||
| 271 | { // ist übersprungen worden | ||
| 272 | if ( ++count, data[--child] >= val ) { // größer als der zu versick- | ||
| 273 | data[parent] = data[child]; // ernde Wert, also noch nach oben | ||
| 274 | data[child] = val; // versickerten Wert eintragen | ||
| 275 | continue; | ||
| 276 | } | ||
| 277 | |||
| 278 | child = parent; // 1 Ebene nach oben zurück | ||
| 279 | } | ||
| 280 | else { | ||
| 281 | if ( ++count, data[parent] >= val ) { // das Blatt ist größer als der | ||
| 282 | data[parent] = val; // zu versickernde Wert, der damit | ||
| 283 | continue; // direkt eingetragen werden kann | ||
| 284 | } | ||
| 285 | |||
| 286 | child = (parent - 1) >> 1; // 2 Ebenen nach oben zurück | ||
| 287 | } | ||
| 288 | |||
| 289 | while ( child != root ) // maximal zum Ausgangspunkt zurück | ||
| 290 | { | ||
| 291 | parent = (child - 1) >> 1; // den Vergleichswert haben wir bereits | ||
| 292 | // nach oben verschoben | ||
| 293 | if ( ++count, data[parent] >= val ) // größer als der zu versickernde | ||
| 294 | break; // Wert, also Position gefunden | ||
| 295 | |||
| 296 | data[child] = data[parent]; // Rückverschiebung nötig | ||
| 297 | child = parent; // 1 Ebene nach oben zurück | ||
| 298 | } | ||
| 299 | |||
| 300 | data[child] = val; // versickerten Wert eintragen | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | /*----------------------------------------------------------------------*/ | ||
| 305 | /* BOTTOM-UP HEAPSORT */ | ||
| 306 | /* Written by J. Teuhola <teuhola@cs.utu.fi>; the original idea is */ | ||
| 307 | /* probably due to R.W. Floyd. Thereafter it has been used by many */ | ||
| 308 | /* authors, among others S. Carlsson and I. Wegener. Building the heap */ | ||
| 309 | /* bottom-up is also due to R. W. Floyd: Treesort 3 (Algorithm 245), */ | ||
| 310 | /* Communications of the ACM 7, p. 701, 1964. */ | ||
| 311 | /*----------------------------------------------------------------------*/ | ||
| 312 | |||
| 313 | #define element float | ||
| 314 | |||
| 315 | /*-----------------------------------------------------------------------*/ | ||
| 316 | /* The sift-up procedure sinks a hole from v[i] to leaf and then sifts */ | ||
| 317 | /* the original v[i] element from the leaf level up. This is the main */ | ||
| 318 | /* idea of bottom-up heapsort. */ | ||
| 319 | /*-----------------------------------------------------------------------*/ | ||
| 320 | static void | ||
| 321 | siftup(T v[], int i, int n) | ||
| 322 | { | ||
| 323 | int j, start; | ||
| 324 | T x; | ||
| 325 | |||
| 326 | start = i; | ||
| 327 | x = v[i]; | ||
| 328 | j = i << 1; | ||
| 329 | while ( j <= n ) { | ||
| 330 | if ( j < n ) | ||
| 331 | if ( v[j] < v[j + 1] ) | ||
| 332 | j++; | ||
| 333 | v[i] = v[j]; | ||
| 334 | i = j; | ||
| 335 | j = i << 1; | ||
| 336 | } | ||
| 337 | j = i >> 1; | ||
| 338 | while ( j >= start ) { | ||
| 339 | if ( v[j] < x ) { | ||
| 340 | v[i] = v[j]; | ||
| 341 | i = j; | ||
| 342 | j = i >> 1; | ||
| 343 | } | ||
| 344 | else | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | v[i] = x; | ||
| 348 | } /* End of siftup */ | ||
| 349 | |||
| 350 | /*----------------------------------------------------------------------*/ | ||
| 351 | /* The heapsort procedure; the original array is r[0..n-1], but here */ | ||
| 352 | /* it is shifted to vector v[1..n], for convenience. */ | ||
| 353 | /*----------------------------------------------------------------------*/ | ||
| 354 | void | ||
| 355 | bottom_up_heapsort(T r[], int n) | ||
| 356 | { | ||
| 357 | int k; | ||
| 358 | T x; | ||
| 359 | T * v; | ||
| 360 | |||
| 361 | v = r - 1; /* The address shift */ | ||
| 362 | |||
| 363 | /* Build the heap bottom-up, using siftup. */ | ||
| 364 | for ( k = n >> 1; k > 1; k-- ) | ||
| 365 | siftup(v, k, n); | ||
| 366 | |||
| 367 | /* The main loop of sorting follows. The root is swapped with the last */ | ||
| 368 | /* leaf after each sift-up. */ | ||
| 369 | for ( k = n; k > 1; k-- ) { | ||
| 370 | siftup(v, 1, k); | ||
| 371 | x = v[k]; | ||
| 372 | v[k] = v[1]; | ||
| 373 | v[1] = x; | ||
| 374 | } | ||
| 375 | } /* End of bottom_up_heapsort */ | ||
| 376 | |||
| 377 | /* ====================== HEAPSORT ======================= */ | ||
| 378 | |||
| 379 | /* ====================== INTROSORT ======================= */ | ||
| 380 | |||
| 381 | static void | ||
| 382 | introsort(T a[], int n, int h) | ||
| 383 | { | ||
| 384 | int i, last; | ||
| 385 | |||
| 386 | if ( n <= CUTOFF ) | ||
| 387 | return; | ||
| 388 | |||
| 389 | if ( --h == 1 ) { | ||
| 390 | my_heapsort(a, n); | ||
| 391 | return; | ||
| 392 | } | ||
| 393 | |||
| 394 | swap(a, 0, bigrand() % n); | ||
| 395 | |||
| 396 | last = 0; | ||
| 397 | for ( i = 1; i < n; ++i ) | ||
| 398 | if ( a[i] < a[0] ) | ||
| 399 | swap(a, ++last, i); | ||
| 400 | |||
| 401 | swap(a, 0, last); | ||
| 402 | |||
| 403 | introsort(a, last, h); | ||
| 404 | introsort(a + last + 1, n - last - 1, h); | ||
| 405 | } | ||
| 406 | |||
| 407 | void | ||
| 408 | my_introsort(T a[], int n) | ||
| 409 | { | ||
| 410 | int h = 1; | ||
| 411 | |||
| 412 | for ( int nn = 1; nn < n; nn <<= 1 ) | ||
| 413 | ++h; | ||
| 414 | |||
| 415 | introsort(a, n, h); | ||
| 416 | insertsort(a, n); | ||
| 417 | } | ||
| 418 | |||
| 419 | static void | ||
| 420 | pp_quicksort_impl(T a[], int l, int u) | ||
| 421 | { | ||
| 422 | if ( u - l < CUTOFF ) | ||
| 423 | return; | ||
| 424 | |||
| 425 | swap(a, l, randint(l, u)); | ||
| 426 | |||
| 427 | T t = a[l]; | ||
| 428 | int i = l; | ||
| 429 | int j = u + 1; | ||
| 430 | for ( ;; ) { | ||
| 431 | do | ||
| 432 | i++; | ||
| 433 | while ( /*i <= u &&*/ a[i] < t ); | ||
| 434 | do | ||
| 435 | j--; | ||
| 436 | while ( a[j] > t ); | ||
| 437 | if ( i > j ) | ||
| 438 | break; | ||
| 439 | swap(a, i, j); | ||
| 440 | } | ||
| 441 | swap(a, l, j); | ||
| 442 | pp_quicksort_impl(a, l, j - 1); | ||
| 443 | pp_quicksort_impl(a, j + 1, u); | ||
| 444 | } | ||
| 445 | |||
| 446 | void | ||
| 447 | pp_quicksort(T a[], int n) | ||
| 448 | { | ||
| 449 | pp_quicksort_impl(a, 0, n - 1); | ||
| 450 | insertsort(a, n); | ||
| 451 | } | ||
| 452 | |||
| 453 | static void | ||
| 454 | pp_quicksort_impl_it(T a[], int l, int u, int h) | ||
| 455 | { | ||
| 456 | if ( --h == 1 ) { | ||
| 457 | my_heapsort(a + l, u - l + 1); | ||
| 458 | return; | ||
| 459 | } | ||
| 460 | |||
| 461 | while ( u - l >= CUTOFF ) { | ||
| 462 | swap(a, l, randint(l, u)); | ||
| 463 | |||
| 464 | T t = a[l]; | ||
| 465 | int i = l; | ||
| 466 | int j = u + 1; | ||
| 467 | |||
| 468 | for ( ;; ) { | ||
| 469 | do | ||
| 470 | i++; | ||
| 471 | while ( /*i <= u && */ a[i] < t ); | ||
| 472 | do | ||
| 473 | j--; | ||
| 474 | while ( a[j] > t ); | ||
| 475 | if ( i > j ) | ||
| 476 | break; | ||
| 477 | swap(a, i, j); | ||
| 478 | } | ||
| 479 | swap(a, l, j); | ||
| 480 | |||
| 481 | if ( j - l < u - j ) { | ||
| 482 | pp_quicksort_impl_it(a, l, j - 1, h); | ||
| 483 | l = j + 1; | ||
| 484 | } | ||
| 485 | else { | ||
| 486 | pp_quicksort_impl_it(a, j + 1, u, h); | ||
| 487 | u = j - 1; | ||
| 488 | } | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | void | ||
| 493 | pp_quicksort_it(T a[], int n) | ||
| 494 | { | ||
| 495 | int h = 1; | ||
| 496 | |||
| 497 | for ( int nn = 1; nn < n; nn <<= 1 ) | ||
| 498 | ++h; | ||
| 499 | |||
| 500 | pp_quicksort_impl_it(a, 0, n - 1, h); | ||
| 501 | insertsort(a, n); | ||
| 502 | } | ||
| 503 | |||
| 504 | int | ||
| 505 | binary_search(T x, T v[], int n) | ||
| 506 | { | ||
| 507 | int low, high; | ||
| 508 | |||
| 509 | low = 0; | ||
| 510 | high = n - 1; | ||
| 511 | while ( low <= high ) { | ||
| 512 | int mid = low + ((high - low) / 2); | ||
| 513 | if ( x > v[mid] ) | ||
| 514 | low = mid + 1; | ||
| 515 | else if ( x < v[mid] ) | ||
| 516 | high = mid - 1; | ||
| 517 | else | ||
| 518 | return mid; | ||
| 519 | } | ||
| 520 | return -1; | ||
| 521 | } | ||
| 522 | |||
| 523 | int | ||
| 524 | lower_bound(T x, T v[], int n) | ||
| 525 | { | ||
| 526 | int low, high; | ||
| 527 | |||
| 528 | low = 0; | ||
| 529 | high = n; | ||
| 530 | while ( low < high ) { | ||
| 531 | int mid = low + ((high - low) / 2); | ||
| 532 | |||
| 533 | if ( x > v[mid] ) | ||
| 534 | low = mid + 1; | ||
| 535 | else | ||
| 536 | high = mid; | ||
| 537 | } | ||
| 538 | return x == v[low] ? low : -1; | ||
| 539 | } | ||
| 540 | |||
| 541 | int | ||
| 542 | upper_bound(T x, T v[], int n) | ||
| 543 | { | ||
| 544 | int low, high; | ||
| 545 | |||
| 546 | low = 0; | ||
| 547 | high = n; | ||
| 548 | while ( low < high ) { | ||
| 549 | int mid = low + ((high - low) / 2); | ||
| 550 | |||
| 551 | if ( x >= v[mid] ) | ||
| 552 | low = mid + 1; | ||
| 553 | else | ||
| 554 | high = mid; | ||
| 555 | } | ||
| 556 | return (low > 0 && x == v[low - 1]) ? low - 1 : -1; | ||
| 557 | } | ||
| 558 | |||
| 559 | /* TESTTREIBER */ | ||
| 560 | |||
| 561 | void | ||
| 562 | gen_testset_random(T a[], int n) | ||
| 563 | { | ||
| 564 | for ( int i = 0; i < n; ++i ) | ||
| 565 | a[i] = bigrand(); | ||
| 566 | } | ||
| 567 | |||
| 568 | void | ||
| 569 | gen_testset_random2(T a[], int n) | ||
| 570 | { | ||
| 571 | for ( int i = 0; i < n; ++i ) | ||
| 572 | a[i] = bigrand() % 100; | ||
| 573 | } | ||
| 574 | |||
| 575 | void | ||
| 576 | gen_testset_asc(T a[], int n) | ||
| 577 | { | ||
| 578 | for ( int i = 0; i < n; ++i ) | ||
| 579 | a[i] = i; | ||
| 580 | } | ||
| 581 | |||
| 582 | void | ||
| 583 | gen_testset_desc(T a[], int n) | ||
| 584 | { | ||
| 585 | for ( int i = n; i >= 0; --i ) | ||
| 586 | a[i] = i; | ||
| 587 | } | ||
| 588 | |||
| 589 | void | ||
| 590 | gen_testset_unique(T a[], int n) | ||
| 591 | { | ||
| 592 | for ( int i = 0; i < n; ++i ) | ||
| 593 | a[i] = 1; | ||
| 594 | } | ||
| 595 | |||
| 596 | void | ||
| 597 | test_sorting(T a[], int n) | ||
| 598 | { | ||
| 599 | for ( int i = 1; i < n; ++i ) | ||
| 600 | if ( a[i - 1] > a[i] ) { | ||
| 601 | puts("Fehler!"); | ||
| 602 | exit(EXIT_SUCCESS); | ||
| 603 | } | ||
| 604 | } | ||
| 605 | |||
| 606 | void | ||
| 607 | do_one_test(int n, void (*do_sort)(T a[], int n), void (*gen_testset)(T a[], int n)) | ||
| 608 | { | ||
| 609 | T * a; | ||
| 610 | clock_t start, ende; | ||
| 611 | |||
| 612 | a = malloc(sizeof(T) * (size_t) n); | ||
| 613 | |||
| 614 | (*gen_testset)(a, n); | ||
| 615 | |||
| 616 | start = clock(); | ||
| 617 | (*do_sort)(a, n); | ||
| 618 | ende = clock(); | ||
| 619 | |||
| 620 | test_sorting(a, n); | ||
| 621 | |||
| 622 | free(a); | ||
| 623 | |||
| 624 | printf("%10.3lf sec", ((double) ende - start) / CLOCKS_PER_SEC); | ||
| 625 | fflush(stdout); | ||
| 626 | } | ||
| 627 | |||
| 628 | void | ||
| 629 | do_all_tests(const char *msg, int n, void (*do_sort)(T a[], int n)) | ||
| 630 | { | ||
| 631 | printf("%-15.15s n=%-10d: ", msg, n); | ||
| 632 | do_one_test(n, do_sort, gen_testset_random); | ||
| 633 | do_one_test(n, do_sort, gen_testset_random2); | ||
| 634 | do_one_test(n, do_sort, gen_testset_asc); | ||
| 635 | do_one_test(n, do_sort, gen_testset_desc); | ||
| 636 | do_one_test(n, do_sort, gen_testset_unique); | ||
| 637 | putchar('\n'); | ||
| 638 | } | ||
| 639 | |||
| 640 | /* ENDE TESTTREIBER */ | ||
| 641 | |||
| 642 | int | ||
| 643 | main(void) | ||
| 644 | { | ||
| 645 | const int n = 20000000; | ||
| 646 | |||
| 647 | srand(time(0)); | ||
| 648 | do_all_tests("my_heapsort", n, my_heapsort); | ||
| 649 | do_all_tests("heapsort_bu", n, heapsort_bu); | ||
| 650 | do_all_tests("bottom_up_heapsort", n, bottom_up_heapsort); | ||
| 651 | do_all_tests("c_quicksort", n, c_quicksort); | ||
| 652 | //do_all_tests("g4g_quicksort", n, g4g_quicksort); | ||
| 653 | //do_all_tests("sed_quicksort", n, sed_quicksort); | ||
| 654 | do_all_tests("my_introsort", n, my_introsort); | ||
| 655 | //do_all_tests("my_quicksort", n, my_quicksort); | ||
| 656 | do_all_tests("pp_quicksort", n, pp_quicksort); | ||
| 657 | do_all_tests("pp_quicksort_it", n, pp_quicksort_it); | ||
| 658 | |||
| 659 | return 0; | ||
| 660 | } | ||
| 661 | |||
| 662 | #if 0 | ||
| 663 | int _main(void) | ||
| 664 | { | ||
| 665 | T array[20]; | ||
| 666 | |||
| 667 | for ( int i = 0; i != NELEM(array); ++i ) | ||
| 668 | array[i] = rand() % 10; | ||
| 669 | |||
| 670 | sort(array, NELEM(array)); | ||
| 671 | print(array, NELEM(array)); | ||
| 672 | |||
| 673 | int value; | ||
| 674 | while ( scanf("%d", &value) == 1 && value != -1 ) { | ||
| 675 | int bs = binary_search(value, array, NELEM(array)); | ||
| 676 | int lb = lower_bound(value, array, NELEM(array)); | ||
| 677 | int ub = upper_bound(value, array, NELEM(array)); | ||
| 678 | |||
| 679 | printf("bs: %d - lb: %d - ub: %d\n", bs, lb, ub); | ||
| 680 | } | ||
| 681 | |||
| 682 | return EXIT_SUCCESS; | ||
| 683 | } | ||
| 684 | #endif | ||
diff --git a/src/random.h b/src/random.h new file mode 100644 index 0000000..9094d5b --- /dev/null +++ b/src/random.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #ifndef ITS1_RANDOM_H_INCLUDED | ||
| 2 | #define ITS1_RANDOM_H_INCLUDED | ||
| 3 | |||
| 4 | #ifdef __cplusplus | ||
| 5 | extern "C" { | ||
| 6 | #endif | ||
| 7 | |||
| 8 | struct random_ctx { | ||
| 9 | unsigned char (*get_byte)(struct random_ctx *ctx); | ||
| 10 | }; | ||
| 11 | |||
| 12 | static unsigned char | ||
| 13 | random_get_byte(struct random_ctx *ctx) | ||
| 14 | { | ||
| 15 | return ctx->get_byte(ctx); | ||
| 16 | } | ||
| 17 | |||
| 18 | static unsigned short | ||
| 19 | random_get_word(struct random_ctx *ctx) | ||
| 20 | { | ||
| 21 | return (ctx->get_byte(ctx) << 8) | ||
| 22 | | ctx->get_byte(ctx) | ||
| 23 | ; | ||
| 24 | } | ||
| 25 | |||
| 26 | static unsigned long | ||
| 27 | random_get_dword(struct random_ctx *ctx) | ||
| 28 | { | ||
| 29 | return (ctx->get_byte(ctx) << 24) | ||
| 30 | | (ctx->get_byte(ctx) << 16) | ||
| 31 | | (ctx->get_byte(ctx) << 8) | ||
| 32 | | ctx->get_byte(ctx) | ||
| 33 | ; | ||
| 34 | } | ||
| 35 | |||
| 36 | static unsigned long | ||
| 37 | random_get_dword_range(struct random_ctx *ctx, unsigned long l, unsigned long u) | ||
| 38 | { | ||
| 39 | return l + random_get_dword(ctx) % (u - l + 1); | ||
| 40 | } | ||
| 41 | |||
| 42 | #ifdef __cplusplus | ||
| 43 | } | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #endif /* ITS1_RANDOM_H_INCLUDED */ | ||
| 47 | |||
diff --git a/src/rb.c b/src/rb.c new file mode 100644 index 0000000..7c2d2c1 --- /dev/null +++ b/src/rb.c | |||
| @@ -0,0 +1,614 @@ | |||
| 1 | /* | ||
| 2 | Implementierung übernommen von: https://web.archive.org/web/20140328232325/http://en.literateprograms.org/Red-black_tree_(C) | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <stdio.h> | ||
| 6 | #include <stdlib.h> | ||
| 7 | #include <time.h> | ||
| 8 | |||
| 9 | #include "util.h" | ||
| 10 | |||
| 11 | /* The authors of this work have released all rights to it and placed it | ||
| 12 | in the public domain under the Creative Commons CC0 1.0 waiver | ||
| 13 | (http://creativecommons.org/publicdomain/zero/1.0/). | ||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
| 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
| 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 22 | |||
| 23 | Retrieved from: http://en.literateprograms.org/Red-black_tree_(C)?oldid=19567 | ||
| 24 | */ | ||
| 25 | |||
| 26 | enum rbtree_node_color { RED, | ||
| 27 | BLACK }; | ||
| 28 | |||
| 29 | typedef struct rbtree_node_t { | ||
| 30 | void * key; | ||
| 31 | void * value; | ||
| 32 | struct rbtree_node_t * left; | ||
| 33 | struct rbtree_node_t * right; | ||
| 34 | struct rbtree_node_t * parent; | ||
| 35 | enum rbtree_node_color color; | ||
| 36 | } * rbtree_node; | ||
| 37 | |||
| 38 | typedef struct rbtree_t { | ||
| 39 | rbtree_node root; | ||
| 40 | } * rbtree; | ||
| 41 | |||
| 42 | typedef int (*compare_func)(void *left, void *right); | ||
| 43 | |||
| 44 | rbtree rbtree_create(); | ||
| 45 | void * rbtree_lookup(rbtree t, void *key, compare_func compare); | ||
| 46 | void rbtree_insert(rbtree t, void *key, void *value, compare_func compare); | ||
| 47 | void rbtree_delete(rbtree t, void *key, compare_func compare); | ||
| 48 | |||
| 49 | #include <assert.h> | ||
| 50 | #include <stdlib.h> | ||
| 51 | |||
| 52 | typedef rbtree_node node; | ||
| 53 | typedef enum rbtree_node_color color; | ||
| 54 | |||
| 55 | static node grandparent(node n); | ||
| 56 | static node sibling(node n); | ||
| 57 | static node uncle(node n); | ||
| 58 | static void verify_properties(rbtree t); | ||
| 59 | static void verify_property_1(node root); | ||
| 60 | static void verify_property_2(node root); | ||
| 61 | static color node_color(node n); | ||
| 62 | static void verify_property_4(node root); | ||
| 63 | static void verify_property_5(node root); | ||
| 64 | static void verify_property_5_helper(node n, int black_count, int *black_count_path); | ||
| 65 | |||
| 66 | static node new_node(void *key, void *value, color node_color, node left, node right); | ||
| 67 | static node lookup_node(rbtree t, void *key, compare_func compare); | ||
| 68 | static void rotate_left(rbtree t, node n); | ||
| 69 | static void rotate_right(rbtree t, node n); | ||
| 70 | |||
| 71 | static void replace_node(rbtree t, node oldn, node newn); | ||
| 72 | static void insert_case1(rbtree t, node n); | ||
| 73 | static void insert_case2(rbtree t, node n); | ||
| 74 | static void insert_case3(rbtree t, node n); | ||
| 75 | static void insert_case4(rbtree t, node n); | ||
| 76 | static void insert_case5(rbtree t, node n); | ||
| 77 | static node maximum_node(node root); | ||
| 78 | static void delete_case1(rbtree t, node n); | ||
| 79 | static void delete_case2(rbtree t, node n); | ||
| 80 | static void delete_case3(rbtree t, node n); | ||
| 81 | static void delete_case4(rbtree t, node n); | ||
| 82 | static void delete_case5(rbtree t, node n); | ||
| 83 | static void delete_case6(rbtree t, node n); | ||
| 84 | |||
| 85 | node | ||
| 86 | grandparent(node n) | ||
| 87 | { | ||
| 88 | assert(n != NULL); | ||
| 89 | assert(n->parent != NULL); /* Not the root node */ | ||
| 90 | assert(n->parent->parent != NULL); /* Not child of root */ | ||
| 91 | return n->parent->parent; | ||
| 92 | } | ||
| 93 | |||
| 94 | node | ||
| 95 | sibling(node n) | ||
| 96 | { | ||
| 97 | assert(n != NULL); | ||
| 98 | assert(n->parent != NULL); /* Root node has no sibling */ | ||
| 99 | if ( n == n->parent->left ) | ||
| 100 | return n->parent->right; | ||
| 101 | else | ||
| 102 | return n->parent->left; | ||
| 103 | } | ||
| 104 | |||
| 105 | node | ||
| 106 | uncle(node n) | ||
| 107 | { | ||
| 108 | assert(n != NULL); | ||
| 109 | assert(n->parent != NULL); /* Root node has no uncle */ | ||
| 110 | assert(n->parent->parent != NULL); /* Children of root have no uncle */ | ||
| 111 | return sibling(n->parent); | ||
| 112 | } | ||
| 113 | |||
| 114 | void | ||
| 115 | verify_properties(rbtree t) | ||
| 116 | { | ||
| 117 | (void) t; | ||
| 118 | #ifdef VERIFY_RBTREE | ||
| 119 | verify_property_1(t->root); | ||
| 120 | verify_property_2(t->root); | ||
| 121 | /* Property 3 is implicit */ | ||
| 122 | verify_property_4(t->root); | ||
| 123 | verify_property_5(t->root); | ||
| 124 | #endif | ||
| 125 | } | ||
| 126 | |||
| 127 | void | ||
| 128 | verify_property_1(node n) | ||
| 129 | { | ||
| 130 | assert(node_color(n) == RED || node_color(n) == BLACK); | ||
| 131 | if ( n == NULL ) | ||
| 132 | return; | ||
| 133 | verify_property_1(n->left); | ||
| 134 | verify_property_1(n->right); | ||
| 135 | } | ||
| 136 | |||
| 137 | void | ||
| 138 | verify_property_2(node root) | ||
| 139 | { | ||
| 140 | assert(node_color(root) == BLACK); | ||
| 141 | } | ||
| 142 | |||
| 143 | color | ||
| 144 | node_color(node n) | ||
| 145 | { | ||
| 146 | return n == NULL ? BLACK : n->color; | ||
| 147 | } | ||
| 148 | |||
| 149 | void | ||
| 150 | verify_property_4(node n) | ||
| 151 | { | ||
| 152 | if ( node_color(n) == RED ) { | ||
| 153 | assert(node_color(n->left) == BLACK); | ||
| 154 | assert(node_color(n->right) == BLACK); | ||
| 155 | assert(node_color(n->parent) == BLACK); | ||
| 156 | } | ||
| 157 | if ( n == NULL ) | ||
| 158 | return; | ||
| 159 | verify_property_4(n->left); | ||
| 160 | verify_property_4(n->right); | ||
| 161 | } | ||
| 162 | |||
| 163 | void | ||
| 164 | verify_property_5(node root) | ||
| 165 | { | ||
| 166 | int black_count_path = -1; | ||
| 167 | verify_property_5_helper(root, 0, &black_count_path); | ||
| 168 | } | ||
| 169 | |||
| 170 | void | ||
| 171 | verify_property_5_helper(node n, int black_count, int *path_black_count) | ||
| 172 | { | ||
| 173 | if ( node_color(n) == BLACK ) { | ||
| 174 | black_count++; | ||
| 175 | } | ||
| 176 | if ( n == NULL ) { | ||
| 177 | if ( *path_black_count == -1 ) { | ||
| 178 | *path_black_count = black_count; | ||
| 179 | } | ||
| 180 | else { | ||
| 181 | assert(black_count == *path_black_count); | ||
| 182 | } | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | verify_property_5_helper(n->left, black_count, path_black_count); | ||
| 186 | verify_property_5_helper(n->right, black_count, path_black_count); | ||
| 187 | } | ||
| 188 | |||
| 189 | rbtree | ||
| 190 | rbtree_create() | ||
| 191 | { | ||
| 192 | rbtree t = malloc(sizeof *t); | ||
| 193 | t->root = NULL; | ||
| 194 | verify_properties(t); | ||
| 195 | return t; | ||
| 196 | } | ||
| 197 | |||
| 198 | node | ||
| 199 | new_node(void *key, void *value, color node_color, node left, node right) | ||
| 200 | { | ||
| 201 | node result = malloc(sizeof *result); | ||
| 202 | result->key = key; | ||
| 203 | result->value = value; | ||
| 204 | result->color = node_color; | ||
| 205 | result->left = left; | ||
| 206 | result->right = right; | ||
| 207 | if ( left != NULL ) | ||
| 208 | left->parent = result; | ||
| 209 | if ( right != NULL ) | ||
| 210 | right->parent = result; | ||
| 211 | result->parent = NULL; | ||
| 212 | return result; | ||
| 213 | } | ||
| 214 | |||
| 215 | node | ||
| 216 | lookup_node(rbtree t, void *key, compare_func compare) | ||
| 217 | { | ||
| 218 | node n = t->root; | ||
| 219 | while ( n != NULL ) { | ||
| 220 | int comp_result = compare(key, n->key); | ||
| 221 | if ( comp_result == 0 ) { | ||
| 222 | return n; | ||
| 223 | } | ||
| 224 | else if ( comp_result < 0 ) { | ||
| 225 | n = n->left; | ||
| 226 | } | ||
| 227 | else { | ||
| 228 | assert(comp_result > 0); | ||
| 229 | n = n->right; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | return n; | ||
| 233 | } | ||
| 234 | |||
| 235 | void * | ||
| 236 | rbtree_lookup(rbtree t, void *key, compare_func compare) | ||
| 237 | { | ||
| 238 | node n = lookup_node(t, key, compare); | ||
| 239 | return n == NULL ? NULL : n->value; | ||
| 240 | } | ||
| 241 | |||
| 242 | void | ||
| 243 | rotate_left(rbtree t, node n) | ||
| 244 | { | ||
| 245 | node r = n->right; | ||
| 246 | replace_node(t, n, r); | ||
| 247 | n->right = r->left; | ||
| 248 | if ( r->left != NULL ) { | ||
| 249 | r->left->parent = n; | ||
| 250 | } | ||
| 251 | r->left = n; | ||
| 252 | n->parent = r; | ||
| 253 | } | ||
| 254 | |||
| 255 | void | ||
| 256 | rotate_right(rbtree t, node n) | ||
| 257 | { | ||
| 258 | node L = n->left; | ||
| 259 | replace_node(t, n, L); | ||
| 260 | n->left = L->right; | ||
| 261 | if ( L->right != NULL ) { | ||
| 262 | L->right->parent = n; | ||
| 263 | } | ||
| 264 | L->right = n; | ||
| 265 | n->parent = L; | ||
| 266 | } | ||
| 267 | |||
| 268 | void | ||
| 269 | replace_node(rbtree t, node oldn, node newn) | ||
| 270 | { | ||
| 271 | if ( oldn->parent == NULL ) { | ||
| 272 | t->root = newn; | ||
| 273 | } | ||
| 274 | else { | ||
| 275 | if ( oldn == oldn->parent->left ) | ||
| 276 | oldn->parent->left = newn; | ||
| 277 | else | ||
| 278 | oldn->parent->right = newn; | ||
| 279 | } | ||
| 280 | if ( newn != NULL ) { | ||
| 281 | newn->parent = oldn->parent; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | void | ||
| 286 | rbtree_insert(rbtree t, void *key, void *value, compare_func compare) | ||
| 287 | { | ||
| 288 | node inserted_node = new_node(key, value, RED, NULL, NULL); | ||
| 289 | if ( t->root == NULL ) { | ||
| 290 | t->root = inserted_node; | ||
| 291 | } | ||
| 292 | else { | ||
| 293 | node n = t->root; | ||
| 294 | while ( 1 ) { | ||
| 295 | int comp_result = compare(key, n->key); | ||
| 296 | if ( comp_result == 0 ) { | ||
| 297 | n->value = value; | ||
| 298 | return; | ||
| 299 | } | ||
| 300 | else if ( comp_result < 0 ) { | ||
| 301 | if ( n->left == NULL ) { | ||
| 302 | n->left = inserted_node; | ||
| 303 | break; | ||
| 304 | } | ||
| 305 | else { | ||
| 306 | n = n->left; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | else { | ||
| 310 | assert(comp_result > 0); | ||
| 311 | if ( n->right == NULL ) { | ||
| 312 | n->right = inserted_node; | ||
| 313 | break; | ||
| 314 | } | ||
| 315 | else { | ||
| 316 | n = n->right; | ||
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | inserted_node->parent = n; | ||
| 321 | } | ||
| 322 | insert_case1(t, inserted_node); | ||
| 323 | verify_properties(t); | ||
| 324 | } | ||
| 325 | |||
| 326 | void | ||
| 327 | insert_case1(rbtree t, node n) | ||
| 328 | { | ||
| 329 | if ( n->parent == NULL ) | ||
| 330 | n->color = BLACK; | ||
| 331 | else | ||
| 332 | insert_case2(t, n); | ||
| 333 | } | ||
| 334 | |||
| 335 | void | ||
| 336 | insert_case2(rbtree t, node n) | ||
| 337 | { | ||
| 338 | if ( node_color(n->parent) == BLACK ) | ||
| 339 | return; /* Tree is still valid */ | ||
| 340 | else | ||
| 341 | insert_case3(t, n); | ||
| 342 | } | ||
| 343 | |||
| 344 | void | ||
| 345 | insert_case3(rbtree t, node n) | ||
| 346 | { | ||
| 347 | if ( node_color(uncle(n)) == RED ) { | ||
| 348 | n->parent->color = BLACK; | ||
| 349 | uncle(n)->color = BLACK; | ||
| 350 | grandparent(n)->color = RED; | ||
| 351 | insert_case1(t, grandparent(n)); | ||
| 352 | } | ||
| 353 | else { | ||
| 354 | insert_case4(t, n); | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | void | ||
| 359 | insert_case4(rbtree t, node n) | ||
| 360 | { | ||
| 361 | if ( n == n->parent->right && n->parent == grandparent(n)->left ) { | ||
| 362 | rotate_left(t, n->parent); | ||
| 363 | n = n->left; | ||
| 364 | } | ||
| 365 | else if ( n == n->parent->left && n->parent == grandparent(n)->right ) { | ||
| 366 | rotate_right(t, n->parent); | ||
| 367 | n = n->right; | ||
| 368 | } | ||
| 369 | insert_case5(t, n); | ||
| 370 | } | ||
| 371 | |||
| 372 | void | ||
| 373 | insert_case5(rbtree t, node n) | ||
| 374 | { | ||
| 375 | n->parent->color = BLACK; | ||
| 376 | grandparent(n)->color = RED; | ||
| 377 | if ( n == n->parent->left && n->parent == grandparent(n)->left ) { | ||
| 378 | rotate_right(t, grandparent(n)); | ||
| 379 | } | ||
| 380 | else { | ||
| 381 | assert(n == n->parent->right && n->parent == grandparent(n)->right); | ||
| 382 | rotate_left(t, grandparent(n)); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | void | ||
| 387 | rbtree_delete(rbtree t, void *key, compare_func compare) | ||
| 388 | { | ||
| 389 | node child; | ||
| 390 | node n = lookup_node(t, key, compare); | ||
| 391 | if ( n == NULL ) | ||
| 392 | return; /* Key not found, do nothing */ | ||
| 393 | if ( n->left != NULL && n->right != NULL ) { | ||
| 394 | /* Copy key/value from predecessor and then delete it instead */ | ||
| 395 | node pred = maximum_node(n->left); | ||
| 396 | n->key = pred->key; | ||
| 397 | n->value = pred->value; | ||
| 398 | n = pred; | ||
| 399 | } | ||
| 400 | |||
| 401 | assert(n->left == NULL || n->right == NULL); | ||
| 402 | child = n->right == NULL ? n->left : n->right; | ||
| 403 | if ( node_color(n) == BLACK ) { | ||
| 404 | n->color = node_color(child); | ||
| 405 | delete_case1(t, n); | ||
| 406 | } | ||
| 407 | replace_node(t, n, child); | ||
| 408 | if ( n->parent == NULL && child != NULL ) // root should be black | ||
| 409 | child->color = BLACK; | ||
| 410 | free(n); | ||
| 411 | |||
| 412 | verify_properties(t); | ||
| 413 | } | ||
| 414 | |||
| 415 | static node | ||
| 416 | maximum_node(node n) | ||
| 417 | { | ||
| 418 | assert(n != NULL); | ||
| 419 | while ( n->right != NULL ) { | ||
| 420 | n = n->right; | ||
| 421 | } | ||
| 422 | return n; | ||
| 423 | } | ||
| 424 | |||
| 425 | void | ||
| 426 | delete_case1(rbtree t, node n) | ||
| 427 | { | ||
| 428 | if ( n->parent == NULL ) | ||
| 429 | return; | ||
| 430 | else | ||
| 431 | delete_case2(t, n); | ||
| 432 | } | ||
| 433 | |||
| 434 | void | ||
| 435 | delete_case2(rbtree t, node n) | ||
| 436 | { | ||
| 437 | if ( node_color(sibling(n)) == RED ) { | ||
| 438 | n->parent->color = RED; | ||
| 439 | sibling(n)->color = BLACK; | ||
| 440 | if ( n == n->parent->left ) | ||
| 441 | rotate_left(t, n->parent); | ||
| 442 | else | ||
| 443 | rotate_right(t, n->parent); | ||
| 444 | } | ||
| 445 | delete_case3(t, n); | ||
| 446 | } | ||
| 447 | |||
| 448 | void | ||
| 449 | delete_case3(rbtree t, node n) | ||
| 450 | { | ||
| 451 | if ( node_color(n->parent) == BLACK && | ||
| 452 | node_color(sibling(n)) == BLACK && | ||
| 453 | node_color(sibling(n)->left) == BLACK && | ||
| 454 | node_color(sibling(n)->right) == BLACK ) { | ||
| 455 | sibling(n)->color = RED; | ||
| 456 | delete_case1(t, n->parent); | ||
| 457 | } | ||
| 458 | else | ||
| 459 | delete_case4(t, n); | ||
| 460 | } | ||
| 461 | |||
| 462 | void | ||
| 463 | delete_case4(rbtree t, node n) | ||
| 464 | { | ||
| 465 | if ( node_color(n->parent) == RED && | ||
| 466 | node_color(sibling(n)) == BLACK && | ||
| 467 | node_color(sibling(n)->left) == BLACK && | ||
| 468 | node_color(sibling(n)->right) == BLACK ) { | ||
| 469 | sibling(n)->color = RED; | ||
| 470 | n->parent->color = BLACK; | ||
| 471 | } | ||
| 472 | else | ||
| 473 | delete_case5(t, n); | ||
| 474 | } | ||
| 475 | |||
| 476 | void | ||
| 477 | delete_case5(rbtree t, node n) | ||
| 478 | { | ||
| 479 | if ( n == n->parent->left && | ||
| 480 | node_color(sibling(n)) == BLACK && | ||
| 481 | node_color(sibling(n)->left) == RED && | ||
| 482 | node_color(sibling(n)->right) == BLACK ) { | ||
| 483 | sibling(n)->color = RED; | ||
| 484 | sibling(n)->left->color = BLACK; | ||
| 485 | rotate_right(t, sibling(n)); | ||
| 486 | } | ||
| 487 | else if ( n == n->parent->right && | ||
| 488 | node_color(sibling(n)) == BLACK && | ||
| 489 | node_color(sibling(n)->right) == RED && | ||
| 490 | node_color(sibling(n)->left) == BLACK ) { | ||
| 491 | sibling(n)->color = RED; | ||
| 492 | sibling(n)->right->color = BLACK; | ||
| 493 | rotate_left(t, sibling(n)); | ||
| 494 | } | ||
| 495 | delete_case6(t, n); | ||
| 496 | } | ||
| 497 | |||
| 498 | void | ||
| 499 | delete_case6(rbtree t, node n) | ||
| 500 | { | ||
| 501 | sibling(n)->color = node_color(n->parent); | ||
| 502 | n->parent->color = BLACK; | ||
| 503 | if ( n == n->parent->left ) { | ||
| 504 | assert(node_color(sibling(n)->right) == RED); | ||
| 505 | sibling(n)->right->color = BLACK; | ||
| 506 | rotate_left(t, n->parent); | ||
| 507 | } | ||
| 508 | else { | ||
| 509 | assert(node_color(sibling(n)->left) == RED); | ||
| 510 | sibling(n)->left->color = BLACK; | ||
| 511 | rotate_right(t, n->parent); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 515 | /* The authors of this work have released all rights to it and placed it | ||
| 516 | in the public domain under the Creative Commons CC0 1.0 waiver | ||
| 517 | (http://creativecommons.org/publicdomain/zero/1.0/). | ||
| 518 | |||
| 519 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 520 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 521 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| 522 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
| 523 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| 524 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
| 525 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 526 | |||
| 527 | Retrieved from: http://en.literateprograms.org/Red-black_tree_(C)?oldid=19567 | ||
| 528 | */ | ||
| 529 | |||
| 530 | #include <assert.h> | ||
| 531 | #include <stdio.h> | ||
| 532 | #include <stdlib.h> /* rand() */ | ||
| 533 | |||
| 534 | static int compare_int(void *left, void *right); | ||
| 535 | static void print_tree(rbtree t); | ||
| 536 | static void print_tree_helper(rbtree_node n, int indent); | ||
| 537 | |||
| 538 | int | ||
| 539 | compare_int(void *leftp, void *rightp) | ||
| 540 | { | ||
| 541 | int left = (int) leftp; | ||
| 542 | int right = (int) rightp; | ||
| 543 | if ( left < right ) | ||
| 544 | return -1; | ||
| 545 | else if ( left > right ) | ||
| 546 | return 1; | ||
| 547 | else { | ||
| 548 | assert(left == right); | ||
| 549 | return 0; | ||
| 550 | } | ||
| 551 | } | ||
| 552 | |||
| 553 | #define INDENT_STEP 4 | ||
| 554 | |||
| 555 | void print_tree_helper(rbtree_node n, int indent); | ||
| 556 | |||
| 557 | void | ||
| 558 | print_tree(rbtree t) | ||
| 559 | { | ||
| 560 | print_tree_helper(t->root, 0); | ||
| 561 | puts(""); | ||
| 562 | } | ||
| 563 | |||
| 564 | void | ||
| 565 | print_tree_helper(rbtree_node n, int indent) | ||
| 566 | { | ||
| 567 | int i; | ||
| 568 | if ( n == NULL ) { | ||
| 569 | fputs("<empty tree>", stdout); | ||
| 570 | return; | ||
| 571 | } | ||
| 572 | if ( n->right != NULL ) { | ||
| 573 | print_tree_helper(n->right, indent + INDENT_STEP); | ||
| 574 | } | ||
| 575 | for ( i = 0; i < indent; i++ ) | ||
| 576 | fputs(" ", stdout); | ||
| 577 | if ( n->color == BLACK ) | ||
| 578 | printf("%d\n", (int) n->key); | ||
| 579 | else | ||
| 580 | printf("<%d>\n", (int) n->key); | ||
| 581 | if ( n->left != NULL ) { | ||
| 582 | print_tree_helper(n->left, indent + INDENT_STEP); | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | int | ||
| 587 | main() | ||
| 588 | { | ||
| 589 | int i; | ||
| 590 | rbtree t = rbtree_create(); | ||
| 591 | |||
| 592 | for ( i = 0; i < 50; i++ ) { | ||
| 593 | long x = rand() % 10000; | ||
| 594 | long y = rand() % 10000; | ||
| 595 | #ifdef TRACE | ||
| 596 | print_tree(t); | ||
| 597 | printf("Inserting %ld -> %ld\n\n", x, y); | ||
| 598 | #endif | ||
| 599 | rbtree_insert(t, (void *) x, (void *) y, compare_int); | ||
| 600 | assert(rbtree_lookup(t, (void *) x, compare_int) == (void *) y); | ||
| 601 | } | ||
| 602 | |||
| 603 | print_tree(t); | ||
| 604 | |||
| 605 | for ( i = 0; i < 60000; i++ ) { | ||
| 606 | long x = rand() % 10000; | ||
| 607 | #ifdef TRACE | ||
| 608 | print_tree(t); | ||
| 609 | printf("Deleting key %ld\n\n", x); | ||
| 610 | #endif | ||
| 611 | rbtree_delete(t, (void *) x, compare_int); | ||
| 612 | } | ||
| 613 | return 0; | ||
| 614 | } | ||
diff --git a/src/rc4.c b/src/rc4.c new file mode 100644 index 0000000..8a67303 --- /dev/null +++ b/src/rc4.c | |||
| @@ -0,0 +1,156 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <string.h> /* memset() */ | ||
| 4 | |||
| 5 | #include "random.h" | ||
| 6 | #include "util.h" | ||
| 7 | |||
| 8 | struct rc4_ctx { | ||
| 9 | struct random_ctx ctx; | ||
| 10 | |||
| 11 | unsigned int i; | ||
| 12 | unsigned int j; | ||
| 13 | unsigned char S[256]; | ||
| 14 | }; | ||
| 15 | |||
| 16 | static void | ||
| 17 | swap(unsigned char a[], unsigned int i, unsigned int j) | ||
| 18 | { | ||
| 19 | unsigned char t = a[i]; | ||
| 20 | a[i] = a[j]; | ||
| 21 | a[j] = t; | ||
| 22 | } | ||
| 23 | |||
| 24 | unsigned char | ||
| 25 | rc4_get_byte(struct rc4_ctx *ctx) | ||
| 26 | { | ||
| 27 | ctx->i = (ctx->i + 1) % 256; | ||
| 28 | ctx->j = (ctx->j + ctx->S[ctx->i]) % 256; | ||
| 29 | swap(ctx->S, ctx->i, ctx->j); | ||
| 30 | |||
| 31 | return ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256]; | ||
| 32 | } | ||
| 33 | |||
| 34 | void | ||
| 35 | rc4_init(struct rc4_ctx *ctx, void *key, size_t sz) | ||
| 36 | { | ||
| 37 | const unsigned char *K = key; | ||
| 38 | unsigned int i, j; | ||
| 39 | |||
| 40 | for ( i = 0; i != 256; ++i ) | ||
| 41 | ctx->S[i] = i; | ||
| 42 | |||
| 43 | for ( i = j = 0; i != 256; ++i ) { | ||
| 44 | j = (j + ctx->S[i] + K[i % sz]) % 256; | ||
| 45 | swap(ctx->S, i, j); | ||
| 46 | } | ||
| 47 | |||
| 48 | ctx->i = 0; | ||
| 49 | ctx->j = 0; | ||
| 50 | ctx->ctx.get_byte = (unsigned char (*)(struct random_ctx *)) rc4_get_byte; | ||
| 51 | } | ||
| 52 | |||
| 53 | void | ||
| 54 | rc4_clear(struct rc4_ctx *ctx) | ||
| 55 | { | ||
| 56 | memset(ctx, 0, sizeof *ctx); | ||
| 57 | } | ||
| 58 | |||
| 59 | struct random_ctx * | ||
| 60 | rc4_create(void *key, size_t sz) | ||
| 61 | { | ||
| 62 | struct rc4_ctx *ctx; | ||
| 63 | |||
| 64 | ctx = malloc(sizeof(*ctx)); | ||
| 65 | if ( ctx ) { | ||
| 66 | rc4_init(ctx, key, sz); | ||
| 67 | |||
| 68 | return &(ctx->ctx); | ||
| 69 | } | ||
| 70 | |||
| 71 | return NULL; | ||
| 72 | } | ||
| 73 | |||
| 74 | void | ||
| 75 | rc4_free(struct random_ctx *ctx) | ||
| 76 | { | ||
| 77 | rc4_clear((struct rc4_ctx *) ctx); | ||
| 78 | free(ctx); | ||
| 79 | } | ||
| 80 | |||
| 81 | void | ||
| 82 | rc4_test(void) | ||
| 83 | { | ||
| 84 | static struct { | ||
| 85 | char * key; | ||
| 86 | unsigned int sz; | ||
| 87 | struct { | ||
| 88 | unsigned int pos; | ||
| 89 | unsigned char bytes[16]; | ||
| 90 | } test[18]; | ||
| 91 | } cases[] = { | ||
| 92 | { "\x01\x02\x03\x04\x05", 5, { { 0, "\xb2\x39\x63\x05\xf0\x3d\xc0\x27\xcc\xc3\x52\x4a\x0a\x11\x18\xa8" }, { 16, "\x69\x82\x94\x4f\x18\xfc\x82\xd5\x89\xc4\x03\xa4\x7a\x0d\x09\x19" }, { 240, "\x28\xcb\x11\x32\xc9\x6c\xe2\x86\x42\x1d\xca\xad\xb8\xb6\x9e\xae" }, { 256, "\x1c\xfc\xf6\x2b\x03\xed\xdb\x64\x1d\x77\xdf\xcf\x7f\x8d\x8c\x93" }, { 496, "\x42\xb7\xd0\xcd\xd9\x18\xa8\xa3\x3d\xd5\x17\x81\xc8\x1f\x40\x41" }, { 512, "\x64\x59\x84\x44\x32\xa7\xda\x92\x3c\xfb\x3e\xb4\x98\x06\x61\xf6" }, { 752, "\xec\x10\x32\x7b\xde\x2b\xee\xfd\x18\xf9\x27\x76\x80\x45\x7e\x22" }, { 768, "\xeb\x62\x63\x8d\x4f\x0b\xa1\xfe\x9f\xca\x20\xe0\x5b\xf8\xff\x2b" }, { 1008, "\x45\x12\x90\x48\xe6\xa0\xed\x0b\x56\xb4\x90\x33\x8f\x07\x8d\xa5" }, { 1024, "\x30\xab\xbc\xc7\xc2\x0b\x01\x60\x9f\x23\xee\x2d\x5f\x6b\xb7\xdf" }, { 1520, "\x32\x94\xf7\x44\xd8\xf9\x79\x05\x07\xe7\x0f\x62\xe5\xbb\xce\xea" }, { 1536, "\xd8\x72\x9d\xb4\x18\x82\x25\x9b\xee\x4f\x82\x53\x25\xf5\xa1\x30" }, { 2032, "\x1e\xb1\x4a\x0c\x13\xb3\xbf\x47\xfa\x2a\x0b\xa9\x3a\xd4\x5b\x8b" }, { 2048, "\xcc\x58\x2f\x8b\xa9\xf2\x65\xe2\xb1\xbe\x91\x12\xe9\x75\xd2\xd7" }, { 3056, "\xf2\xe3\x0f\x9b\xd1\x02\xec\xbf\x75\xaa\xad\xe9\xbc\x35\xc4\x3c" }, { 3072, "\xec\x0e\x11\xc4\x79\xdc\x32\x9d\xc8\xda\x79\x68\xfe\x96\x56\x81" }, { 4080, "\x06\x83\x26\xa2\x11\x84\x16\xd2\x1f\x9d\x04\xb2\xcd\x1c\xa0\x50" }, { 4096, "\xff\x25\xb5\x89\x95\x99\x67\x07\xe5\x1f\xbd\xf0\x8b\x34\xd8\x75" } } }, | ||
| 93 | { "\x01\x02\x03\x04\x05\x06\x07", 7, { { 0, "\x29\x3f\x02\xd4\x7f\x37\xc9\xb6\x33\xf2\xaf\x52\x85\xfe\xb4\x6b" }, { 16, "\xe6\x20\xf1\x39\x0d\x19\xbd\x84\xe2\xe0\xfd\x75\x20\x31\xaf\xc1" }, { 240, "\x91\x4f\x02\x53\x1c\x92\x18\x81\x0d\xf6\x0f\x67\xe3\x38\x15\x4c" }, { 256, "\xd0\xfd\xb5\x83\x07\x3c\xe8\x5a\xb8\x39\x17\x74\x0e\xc0\x11\xd5" }, { 496, "\x75\xf8\x14\x11\xe8\x71\xcf\xfa\x70\xb9\x0c\x74\xc5\x92\xe4\x54" }, { 512, "\x0b\xb8\x72\x02\x93\x8d\xad\x60\x9e\x87\xa5\xa1\xb0\x79\xe5\xe4" }, { 752, "\xc2\x91\x12\x46\xb6\x12\xe7\xe7\xb9\x03\xdf\xed\xa1\xda\xd8\x66" }, { 768, "\x32\x82\x8f\x91\x50\x2b\x62\x91\x36\x8d\xe8\x08\x1d\xe3\x6f\xc2" }, { 1008, "\xf3\xb9\xa7\xe3\xb2\x97\xbf\x9a\xd8\x04\x51\x2f\x90\x63\xef\xf1" }, { 1024, "\x8e\xcb\x67\xa9\xba\x1f\x55\xa5\xa0\x67\xe2\xb0\x26\xa3\x67\x6f" }, { 1520, "\xd2\xaa\x90\x2b\xd4\x2d\x0d\x7c\xfd\x34\x0c\xd4\x58\x10\x52\x9f" }, { 1536, "\x78\xb2\x72\xc9\x6e\x42\xea\xb4\xc6\x0b\xd9\x14\xe3\x9d\x06\xe3" }, { 2032, "\xf4\x33\x2f\xd3\x1a\x07\x93\x96\xee\x3c\xee\x3f\x2a\x4f\xf0\x49" }, { 2048, "\x05\x45\x97\x81\xd4\x1f\xda\x7f\x30\xc1\xbe\x7e\x12\x46\xc6\x23" }, { 3056, "\xad\xfd\x38\x68\xb8\xe5\x14\x85\xd5\xe6\x10\x01\x7e\x3d\xd6\x09" }, { 3072, "\xad\x26\x58\x1c\x0c\x5b\xe4\x5f\x4c\xea\x01\xdb\x2f\x38\x05\xd5" }, { 4080, "\xf3\x17\x2c\xef\xfc\x3b\x3d\x99\x7c\x85\xcc\xd5\xaf\x1a\x95\x0c" }, { 4096, "\xe7\x4b\x0b\x97\x31\x22\x7f\xd3\x7c\x0e\xc0\x8a\x47\xdd\xd8\xb8" } } }, | ||
| 94 | { "\x01\x02\x03\x04\x05\x06\x07\x08", 8, { { 0, "\x97\xab\x8a\x1b\xf0\xaf\xb9\x61\x32\xf2\xf6\x72\x58\xda\x15\xa8" }, { 16, "\x82\x63\xef\xdb\x45\xc4\xa1\x86\x84\xef\x87\xe6\xb1\x9e\x5b\x09" }, { 240, "\x96\x36\xeb\xc9\x84\x19\x26\xf4\xf7\xd1\xf3\x62\xbd\xdf\x6e\x18" }, { 256, "\xd0\xa9\x90\xff\x2c\x05\xfe\xf5\xb9\x03\x73\xc9\xff\x4b\x87\x0a" }, { 496, "\x73\x23\x9f\x1d\xb7\xf4\x1d\x80\xb6\x43\xc0\xc5\x25\x18\xec\x63" }, { 512, "\x16\x3b\x31\x99\x23\xa6\xbd\xb4\x52\x7c\x62\x61\x26\x70\x3c\x0f" }, { 752, "\x49\xd6\xc8\xaf\x0f\x97\x14\x4a\x87\xdf\x21\xd9\x14\x72\xf9\x66" }, { 768, "\x44\x17\x3a\x10\x3b\x66\x16\xc5\xd5\xad\x1c\xee\x40\xc8\x63\xd0" }, { 1008, "\x27\x3c\x9c\x4b\x27\xf3\x22\xe4\xe7\x16\xef\x53\xa4\x7d\xe7\xa4" }, { 1024, "\xc6\xd0\xe7\xb2\x26\x25\x9f\xa9\x02\x34\x90\xb2\x61\x67\xad\x1d" }, { 1520, "\x1f\xe8\x98\x67\x13\xf0\x7c\x3d\x9a\xe1\xc1\x63\xff\x8c\xf9\xd3" }, { 1536, "\x83\x69\xe1\xa9\x65\x61\x0b\xe8\x87\xfb\xd0\xc7\x91\x62\xaa\xfb" }, { 2032, "\x0a\x01\x27\xab\xb4\x44\x84\xb9\xfb\xef\x5a\xbc\xae\x1b\x57\x9f" }, { 2048, "\xc2\xcd\xad\xc6\x40\x2e\x8e\xe8\x66\xe1\xf3\x7b\xdb\x47\xe4\x2c" }, { 3056, "\x26\xb5\x1e\xa3\x7d\xf8\xe1\xd6\xf7\x6f\xc3\xb6\x6a\x74\x29\xb3" }, { 3072, "\xbc\x76\x83\x20\x5d\x4f\x44\x3d\xc1\xf2\x9d\xda\x33\x15\xc8\x7b" }, { 4080, "\xd5\xfa\x5a\x34\x69\xd2\x9a\xaa\xf8\x3d\x23\x58\x9d\xb8\xc8\x5b" }, { 4096, "\x3f\xb4\x6e\x2c\x8f\x0f\x06\x8e\xdc\xe8\xcd\xcd\x7d\xfc\x58\x62" } } }, | ||
| 95 | { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a", 10, { { 0, "\xed\xe3\xb0\x46\x43\xe5\x86\xcc\x90\x7d\xc2\x18\x51\x70\x99\x02" }, { 16, "\x03\x51\x6b\xa7\x8f\x41\x3b\xeb\x22\x3a\xa5\xd4\xd2\xdf\x67\x11" }, { 240, "\x3c\xfd\x6c\xb5\x8e\xe0\xfd\xde\x64\x01\x76\xad\x00\x00\x04\x4d" }, { 256, "\x48\x53\x2b\x21\xfb\x60\x79\xc9\x11\x4c\x0f\xfd\x9c\x04\xa1\xad" }, { 496, "\x3e\x8c\xea\x98\x01\x71\x09\x97\x90\x84\xb1\xef\x92\xf9\x9d\x86" }, { 512, "\xe2\x0f\xb4\x9b\xdb\x33\x7e\xe4\x8b\x8d\x8d\xc0\xf4\xaf\xef\xfe" }, { 752, "\x5c\x25\x21\xea\xcd\x79\x66\xf1\x5e\x05\x65\x44\xbe\xa0\xd3\x15" }, { 768, "\xe0\x67\xa7\x03\x19\x31\xa2\x46\xa6\xc3\x87\x5d\x2f\x67\x8a\xcb" }, { 1008, "\xa6\x4f\x70\xaf\x88\xae\x56\xb6\xf8\x75\x81\xc0\xe2\x3e\x6b\x08" }, { 1024, "\xf4\x49\x03\x1d\xe3\x12\x81\x4e\xc6\xf3\x19\x29\x1f\x4a\x05\x16" }, { 1520, "\xbd\xae\x85\x92\x4b\x3c\xb1\xd0\xa2\xe3\x3a\x30\xc6\xd7\x95\x99" }, { 1536, "\x8a\x0f\xed\xdb\xac\x86\x5a\x09\xbc\xd1\x27\xfb\x56\x2e\xd6\x0a" }, { 2032, "\xb5\x5a\x0a\x5b\x51\xa1\x2a\x8b\xe3\x48\x99\xc3\xe0\x47\x51\x1a" }, { 2048, "\xd9\xa0\x9c\xea\x3c\xe7\x5f\xe3\x96\x98\x07\x03\x17\xa7\x13\x39" }, { 3056, "\x55\x22\x25\xed\x11\x77\xf4\x45\x84\xac\x8c\xfa\x6c\x4e\xb5\xfc" }, { 3072, "\x7e\x82\xcb\xab\xfc\x95\x38\x1b\x08\x09\x98\x44\x21\x29\xc2\xf8" }, { 4080, "\x1f\x13\x5e\xd1\x4c\xe6\x0a\x91\x36\x9d\x23\x22\xbe\xf2\x5e\x3c" }, { 4096, "\x08\xb6\xbe\x45\x12\x4a\x43\xe2\xeb\x77\x95\x3f\x84\xdc\x85\x53" } } }, | ||
| 96 | { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10", 16, { { 0, "\x9a\xc7\xcc\x9a\x60\x9d\x1e\xf7\xb2\x93\x28\x99\xcd\xe4\x1b\x97" }, { 16, "\x52\x48\xc4\x95\x90\x14\x12\x6a\x6e\x8a\x84\xf1\x1d\x1a\x9e\x1c" }, { 240, "\x06\x59\x02\xe4\xb6\x20\xf6\xcc\x36\xc8\x58\x9f\x66\x43\x2f\x2b" }, { 256, "\xd3\x9d\x56\x6b\xc6\xbc\xe3\x01\x07\x68\x15\x15\x49\xf3\x87\x3f" }, { 496, "\xb6\xd1\xe6\xc4\xa5\xe4\x77\x1c\xad\x79\x53\x8d\xf2\x95\xfb\x11" }, { 512, "\xc6\x8c\x1d\x5c\x55\x9a\x97\x41\x23\xdf\x1d\xbc\x52\xa4\x3b\x89" }, { 752, "\xc5\xec\xf8\x8d\xe8\x97\xfd\x57\xfe\xd3\x01\x70\x1b\x82\xa2\x59" }, { 768, "\xec\xcb\xe1\x3d\xe1\xfc\xc9\x1c\x11\xa0\xb2\x6c\x0b\xc8\xfa\x4d" }, { 1008, "\xe7\xa7\x25\x74\xf8\x78\x2a\xe2\x6a\xab\xcf\x9e\xbc\xd6\x60\x65" }, { 1024, "\xbd\xf0\x32\x4e\x60\x83\xdc\xc6\xd3\xce\xdd\x3c\xa8\xc5\x3c\x16" }, { 1520, "\xb4\x01\x10\xc4\x19\x0b\x56\x22\xa9\x61\x16\xb0\x01\x7e\xd2\x97" }, { 1536, "\xff\xa0\xb5\x14\x64\x7e\xc0\x4f\x63\x06\xb8\x92\xae\x66\x11\x81" }, { 2032, "\xd0\x3d\x1b\xc0\x3c\xd3\x3d\x70\xdf\xf9\xfa\x5d\x71\x96\x3e\xbd" }, { 2048, "\x8a\x44\x12\x64\x11\xea\xa7\x8b\xd5\x1e\x8d\x87\xa8\x87\x9b\xf5" }, { 3056, "\xfa\xbe\xb7\x60\x28\xad\xe2\xd0\xe4\x87\x22\xe4\x6c\x46\x15\xa3" }, { 3072, "\xc0\x5d\x88\xab\xd5\x03\x57\xf9\x35\xa6\x3c\x59\xee\x53\x76\x23" }, { 4080, "\xff\x38\x26\x5c\x16\x42\xc1\xab\xe8\xd3\xc2\xfe\x5e\x57\x2b\xf8" }, { 4096, "\xa3\x6a\x4c\x30\x1a\xe8\xac\x13\x61\x0c\xcb\xc1\x22\x56\xca\xcc" } } }, | ||
| 97 | { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18", 24, { { 0, "\x05\x95\xe5\x7f\xe5\xf0\xbb\x3c\x70\x6e\xda\xc8\xa4\xb2\xdb\x11" }, { 16, "\xdf\xde\x31\x34\x4a\x1a\xf7\x69\xc7\x4f\x07\x0a\xee\x9e\x23\x26" }, { 240, "\xb0\x6b\x9b\x1e\x19\x5d\x13\xd8\xf4\xa7\x99\x5c\x45\x53\xac\x05" }, { 256, "\x6b\xd2\x37\x8e\xc3\x41\xc9\xa4\x2f\x37\xba\x79\xf8\x8a\x32\xff" }, { 496, "\xe7\x0b\xce\x1d\xf7\x64\x5a\xdb\x5d\x2c\x41\x30\x21\x5c\x35\x22" }, { 512, "\x9a\x57\x30\xc7\xfc\xb4\xc9\xaf\x51\xff\xda\x89\xc7\xf1\xad\x22" }, { 752, "\x04\x85\x05\x5f\xd4\xf6\xf0\xd9\x63\xef\x5a\xb9\xa5\x47\x69\x82" }, { 768, "\x59\x1f\xc6\x6b\xcd\xa1\x0e\x45\x2b\x03\xd4\x55\x1f\x6b\x62\xac" }, { 1008, "\x27\x53\xcc\x83\x98\x8a\xfa\x3e\x16\x88\xa1\xd3\xb4\x2c\x9a\x02" }, { 1024, "\x93\x61\x0d\x52\x3d\x1d\x3f\x00\x62\xb3\xc2\xa3\xbb\xc7\xc7\xf0" }, { 1520, "\x96\xc2\x48\x61\x0a\xad\xed\xfe\xaf\x89\x78\xc0\x3d\xe8\x20\x5a" }, { 1536, "\x0e\x31\x7b\x3d\x1c\x73\xb9\xe9\xa4\x68\x8f\x29\x6d\x13\x3a\x19" }, { 2032, "\xbd\xf0\xe6\xc3\xcc\xa5\xb5\xb9\xd5\x33\xb6\x9c\x56\xad\xa1\x20" }, { 2048, "\x88\xa2\x18\xb6\xe2\xec\xe1\xe6\x24\x6d\x44\xc7\x59\xd1\x9b\x10" }, { 3056, "\x68\x66\x39\x7e\x95\xc1\x40\x53\x4f\x94\x26\x34\x21\x00\x6e\x40" }, { 3072, "\x32\xcb\x0a\x1e\x95\x42\xc6\xb3\xb8\xb3\x98\xab\xc3\xb0\xf1\xd5" }, { 4080, "\x29\xa0\xb8\xae\xd5\x4a\x13\x23\x24\xc6\x2e\x42\x3f\x54\xb4\xc8" }, { 4096, "\x3c\xb0\xf3\xb5\x02\x0a\x98\xb8\x2a\xf9\xfe\x15\x44\x84\xa1\x68" } } }, | ||
| 98 | { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20", 32, { { 0, "\xea\xa6\xbd\x25\x88\x0b\xf9\x3d\x3f\x5d\x1e\x4c\xa2\x61\x1d\x91" }, { 16, "\xcf\xa4\x5c\x9f\x7e\x71\x4b\x54\xbd\xfa\x80\x02\x7c\xb1\x43\x80" }, { 240, "\x11\x4a\xe3\x44\xde\xd7\x1b\x35\xf2\xe6\x0f\xeb\xad\x72\x7f\xd8" }, { 256, "\x02\xe1\xe7\x05\x6b\x0f\x62\x39\x00\x49\x64\x22\x94\x3e\x97\xb6" }, { 496, "\x91\xcb\x93\xc7\x87\x96\x4e\x10\xd9\x52\x7d\x99\x9c\x6f\x93\x6b" }, { 512, "\x49\xb1\x8b\x42\xf8\xe8\x36\x7c\xbe\xb5\xef\x10\x4b\xa1\xc7\xcd" }, { 752, "\x87\x08\x4b\x3b\xa7\x00\xba\xde\x95\x56\x10\x67\x27\x45\xb3\x74" }, { 768, "\xe7\xa7\xb9\xe9\xec\x54\x0d\x5f\xf4\x3b\xdb\x12\x79\x2d\x1b\x35" }, { 1008, "\xc7\x99\xb5\x96\x73\x8f\x6b\x01\x8c\x76\xc7\x4b\x17\x59\xbd\x90" }, { 1024, "\x7f\xec\x5b\xfd\x9f\x9b\x89\xce\x65\x48\x30\x90\x92\xd7\xe9\x58" }, { 1520, "\x40\xf2\x50\xb2\x6d\x1f\x09\x6a\x4a\xfd\x4c\x34\x0a\x58\x88\x15" }, { 1536, "\x3e\x34\x13\x5c\x79\xdb\x01\x02\x00\x76\x76\x51\xcf\x26\x30\x73" }, { 2032, "\xf6\x56\xab\xcc\xf8\x8d\xd8\x27\x02\x7b\x2c\xe9\x17\xd4\x64\xec" }, { 2048, "\x18\xb6\x25\x03\xbf\xbc\x07\x7f\xba\xbb\x98\xf2\x0d\x98\xab\x34" }, { 3056, "\x8a\xed\x95\xee\x5b\x0d\xcb\xfb\xef\x4e\xb2\x1d\x3a\x3f\x52\xf9" }, { 3072, "\x62\x5a\x1a\xb0\x0e\xe3\x9a\x53\x27\x34\x6b\xdd\xb0\x1a\x9c\x18" }, { 4080, "\xa1\x3a\x7c\x79\xc7\xe1\x19\xb5\xab\x02\x96\xab\x28\xc3\x00\xb9" }, { 4096, "\xf3\xe4\xc0\xa2\xe0\x2d\x1d\x01\xf7\xf0\xa7\x46\x18\xaf\x2b\x48" } } }, | ||
| 99 | { "\x83\x32\x22\x77\x2a", 5, { { 0, "\x80\xad\x97\xbd\xc9\x73\xdf\x8a\x2e\x87\x9e\x92\xa4\x97\xef\xda" }, { 16, "\x20\xf0\x60\xc2\xf2\xe5\x12\x65\x01\xd3\xd4\xfe\xa1\x0d\x5f\xc0" }, { 240, "\xfa\xa1\x48\xe9\x90\x46\x18\x1f\xec\x6b\x20\x85\xf3\xb2\x0e\xd9" }, { 256, "\xf0\xda\xf5\xba\xb3\xd5\x96\x83\x98\x57\x84\x6f\x73\xfb\xfe\x5a" }, { 496, "\x1c\x7e\x2f\xc4\x63\x92\x32\xfe\x29\x75\x84\xb2\x96\x99\x6b\xc8" }, { 512, "\x3d\xb9\xb2\x49\x40\x6c\xc8\xed\xff\xac\x55\xcc\xd3\x22\xba\x12" }, { 752, "\xe4\xf9\xf7\xe0\x06\x61\x54\xbb\xd1\x25\xb7\x45\x56\x9b\xc8\x97" }, { 768, "\x75\xd5\xef\x26\x2b\x44\xc4\x1a\x9c\xf6\x3a\xe1\x45\x68\xe1\xb9" }, { 1008, "\x6d\xa4\x53\xdb\xf8\x1e\x82\x33\x4a\x3d\x88\x66\xcb\x50\xa1\xe3" }, { 1024, "\x78\x28\xd0\x74\x11\x9c\xab\x5c\x22\xb2\x94\xd7\xa9\xbf\xa0\xbb" }, { 1520, "\xad\xb8\x9c\xea\x9a\x15\xfb\xe6\x17\x29\x5b\xd0\x4b\x8c\xa0\x5c" }, { 1536, "\x62\x51\xd8\x7f\xd4\xaa\xae\x9a\x7e\x4a\xd5\xc2\x17\xd3\xf3\x00" }, { 2032, "\xe7\x11\x9b\xd6\xdd\x9b\x22\xaf\xe8\xf8\x95\x85\x43\x28\x81\xe2" }, { 2048, "\x78\x5b\x60\xfd\x7e\xc4\xe9\xfc\xb6\x54\x5f\x35\x0d\x66\x0f\xab" }, { 3056, "\xaf\xec\xc0\x37\xfd\xb7\xb0\x83\x8e\xb3\xd7\x0b\xcd\x26\x83\x82" }, { 3072, "\xdb\xc1\xa7\xb4\x9d\x57\x35\x8c\xc9\xfa\x6d\x61\xd7\x3b\x7c\xf0" }, { 4080, "\x63\x49\xd1\x26\xa3\x7a\xfc\xba\x89\x79\x4f\x98\x04\x91\x4f\xdc" }, { 4096, "\xbf\x42\xc3\x01\x8c\x2f\x7c\x66\xbf\xde\x52\x49\x75\x76\x81\x15" } } }, | ||
| 100 | { "\x19\x10\x83\x32\x22\x77\x2a", 7, { { 0, "\xbc\x92\x22\xdb\xd3\x27\x4d\x8f\xc6\x6d\x14\xcc\xbd\xa6\x69\x0b" }, { 16, "\x7a\xe6\x27\x41\x0c\x9a\x2b\xe6\x93\xdf\x5b\xb7\x48\x5a\x63\xe3" }, { 240, "\x3f\x09\x31\xaa\x03\xde\xfb\x30\x0f\x06\x01\x03\x82\x6f\x2a\x64" }, { 256, "\xbe\xaa\x9e\xc8\xd5\x9b\xb6\x81\x29\xf3\x02\x7c\x96\x36\x11\x81" }, { 496, "\x74\xe0\x4d\xb4\x6d\x28\x64\x8d\x7d\xee\x8a\x00\x64\xb0\x6c\xfe" }, { 512, "\x9b\x5e\x81\xc6\x2f\xe0\x23\xc5\x5b\xe4\x2f\x87\xbb\xf9\x32\xb8" }, { 752, "\xce\x17\x8f\xc1\x82\x6e\xfe\xcb\xc1\x82\xf5\x79\x99\xa4\x61\x40" }, { 768, "\x8b\xdf\x55\xcd\x55\x06\x1c\x06\xdb\xa6\xbe\x11\xde\x4a\x57\x8a" }, { 1008, "\x62\x6f\x5f\x4d\xce\x65\x25\x01\xf3\x08\x7d\x39\xc9\x2c\xc3\x49" }, { 1024, "\x42\xda\xac\x6a\x8f\x9a\xb9\xa7\xfd\x13\x7c\x60\x37\x82\x56\x82" }, { 1520, "\xcc\x03\xfd\xb7\x91\x92\xa2\x07\x31\x2f\x53\xf5\xd4\xdc\x33\xd9" }, { 1536, "\xf7\x0f\x14\x12\x2a\x1c\x98\xa3\x15\x5d\x28\xb8\xa0\xa8\xa4\x1d" }, { 2032, "\x2a\x3a\x30\x7a\xb2\x70\x8a\x9c\x00\xfe\x0b\x42\xf9\xc2\xd6\xa1" }, { 2048, "\x86\x26\x17\x62\x7d\x22\x61\xea\xb0\xb1\x24\x65\x97\xca\x0a\xe9" }, { 3056, "\x55\xf8\x77\xce\x4f\x2e\x1d\xdb\xbf\x8e\x13\xe2\xcd\xe0\xfd\xc8" }, { 3072, "\x1b\x15\x56\xcb\x93\x5f\x17\x33\x37\x70\x5f\xbb\x5d\x50\x1f\xc1" }, { 4080, "\xec\xd0\xe9\x66\x02\xbe\x7f\x8d\x50\x92\x81\x6c\xcc\xf2\xc2\xe9" }, { 4096, "\x02\x78\x81\xfa\xb4\x99\x3a\x1c\x26\x20\x24\xa9\x4f\xff\x3f\x61" } } }, | ||
| 101 | { "\x64\x19\x10\x83\x32\x22\x77\x2a", 8, { { 0, "\xbb\xf6\x09\xde\x94\x13\x17\x2d\x07\x66\x0c\xb6\x80\x71\x69\x26" }, { 16, "\x46\x10\x1a\x6d\xab\x43\x11\x5d\x6c\x52\x2b\x4f\xe9\x36\x04\xa9" }, { 240, "\xcb\xe1\xff\xf2\x1c\x96\xf3\xee\xf6\x1e\x8f\xe0\x54\x2c\xbd\xf0" }, { 256, "\x34\x79\x38\xbf\xfa\x40\x09\xc5\x12\xcf\xb4\x03\x4b\x0d\xd1\xa7" }, { 496, "\x78\x67\xa7\x86\xd0\x0a\x71\x47\x90\x4d\x76\xdd\xf1\xe5\x20\xe3" }, { 512, "\x8d\x3e\x9e\x1c\xae\xfc\xcc\xb3\xfb\xf8\xd1\x8f\x64\x12\x0b\x32" }, { 752, "\x94\x23\x37\xf8\xfd\x76\xf0\xfa\xe8\xc5\x2d\x79\x54\x81\x06\x72" }, { 768, "\xb8\x54\x8c\x10\xf5\x16\x67\xf6\xe6\x0e\x18\x2f\xa1\x9b\x30\xf7" }, { 1008, "\x02\x11\xc7\xc6\x19\x0c\x9e\xfd\x12\x37\xc3\x4c\x8f\x2e\x06\xc4" }, { 1024, "\xbd\xa6\x4f\x65\x27\x6d\x2a\xac\xb8\xf9\x02\x12\x20\x3a\x80\x8e" }, { 1520, "\xbd\x38\x20\xf7\x32\xff\xb5\x3e\xc1\x93\xe7\x9d\x33\xe2\x7c\x73" }, { 1536, "\xd0\x16\x86\x16\x86\x19\x07\xd4\x82\xe3\x6c\xda\xc8\xcf\x57\x49" }, { 2032, "\x97\xb0\xf0\xf2\x24\xb2\xd2\x31\x71\x14\x80\x8f\xb0\x3a\xf7\xa0" }, { 2048, "\xe5\x96\x16\xe4\x69\x78\x79\x39\xa0\x63\xce\xea\x9a\xf9\x56\xd1" }, { 3056, "\xc4\x7e\x0d\xc1\x66\x09\x19\xc1\x11\x01\x20\x8f\x9e\x69\xaa\x1f" }, { 3072, "\x5a\xe4\xf1\x28\x96\xb8\x37\x9a\x2a\xad\x89\xb5\xb5\x53\xd6\xb0" }, { 4080, "\x6b\x6b\x09\x8d\x0c\x29\x3b\xc2\x99\x3d\x80\xbf\x05\x18\xb6\xd9" }, { 4096, "\x81\x70\xcc\x3c\xcd\x92\xa6\x98\x62\x1b\x93\x9d\xd3\x8f\xe7\xb9" } } }, | ||
| 102 | { "\x8b\x37\x64\x19\x10\x83\x32\x22\x77\x2a", 10, { { 0, "\xab\x65\xc2\x6e\xdd\xb2\x87\x60\x0d\xb2\xfd\xa1\x0d\x1e\x60\x5c" }, { 16, "\xbb\x75\x90\x10\xc2\x96\x58\xf2\xc7\x2d\x93\xa2\xd1\x6d\x29\x30" }, { 240, "\xb9\x01\xe8\x03\x6e\xd1\xc3\x83\xcd\x3c\x4c\x4d\xd0\xa6\xab\x05" }, { 256, "\x3d\x25\xce\x49\x22\x92\x4c\x55\xf0\x64\x94\x33\x53\xd7\x8a\x6c" }, { 496, "\x12\xc1\xaa\x44\xbb\xf8\x7e\x75\xe6\x11\xf6\x9b\x2c\x38\xf4\x9b" }, { 512, "\x28\xf2\xb3\x43\x4b\x65\xc0\x98\x77\x47\x00\x44\xc6\xea\x17\x0d" }, { 752, "\xbd\x9e\xf8\x22\xde\x52\x88\x19\x61\x34\xcf\x8a\xf7\x83\x93\x04" }, { 768, "\x67\x55\x9c\x23\xf0\x52\x15\x84\x70\xa2\x96\xf7\x25\x73\x5a\x32" }, { 1008, "\x8b\xab\x26\xfb\xc2\xc1\x2b\x0f\x13\xe2\xab\x18\x5e\xab\xf2\x41" }, { 1024, "\x31\x18\x5a\x6d\x69\x6f\x0c\xfa\x9b\x42\x80\x8b\x38\xe1\x32\xa2" }, { 1520, "\x56\x4d\x3d\xae\x18\x3c\x52\x34\xc8\xaf\x1e\x51\x06\x1c\x44\xb5" }, { 1536, "\x3c\x07\x78\xa7\xb5\xf7\x2d\x3c\x23\xa3\x13\x5c\x7d\x67\xb9\xf4" }, { 2032, "\xf3\x43\x69\x89\x0f\xcf\x16\xfb\x51\x7d\xca\xae\x44\x63\xb2\xdd" }, { 2048, "\x02\xf3\x1c\x81\xe8\x20\x07\x31\xb8\x99\xb0\x28\xe7\x91\xbf\xa7" }, { 3056, "\x72\xda\x64\x62\x83\x22\x8c\x14\x30\x08\x53\x70\x17\x95\x61\x6f" }, { 3072, "\x4e\x0a\x8c\x6f\x79\x34\xa7\x88\xe2\x26\x5e\x81\xd6\xd0\xc8\xf4" }, { 4080, "\x43\x8d\xd5\xea\xfe\xa0\x11\x1b\x6f\x36\xb4\xb9\x38\xda\x2a\x68" }, { 4096, "\x5f\x6b\xfc\x73\x81\x58\x74\xd9\x71\x00\xf0\x86\x97\x93\x57\xd8" } } }, | ||
| 103 | { "\xeb\xb4\x62\x27\xc6\xcc\x8b\x37\x64\x19\x10\x83\x32\x22\x77\x2a", 16, { { 0, "\x72\x0c\x94\xb6\x3e\xdf\x44\xe1\x31\xd9\x50\xca\x21\x1a\x5a\x30" }, { 16, "\xc3\x66\xfd\xea\xcf\x9c\xa8\x04\x36\xbe\x7c\x35\x84\x24\xd2\x0b" }, { 240, "\xb3\x39\x4a\x40\xaa\xbf\x75\xcb\xa4\x22\x82\xef\x25\xa0\x05\x9f" }, { 256, "\x48\x47\xd8\x1d\xa4\x94\x2d\xbc\x24\x9d\xef\xc4\x8c\x92\x2b\x9f" }, { 496, "\x08\x12\x8c\x46\x9f\x27\x53\x42\xad\xda\x20\x2b\x2b\x58\xda\x95" }, { 512, "\x97\x0d\xac\xef\x40\xad\x98\x72\x3b\xac\x5d\x69\x55\xb8\x17\x61" }, { 752, "\x3c\xb8\x99\x93\xb0\x7b\x0c\xed\x93\xde\x13\xd2\xa1\x10\x13\xac" }, { 768, "\xef\x2d\x67\x6f\x15\x45\xc2\xc1\x3d\xc6\x80\xa0\x2f\x4a\xdb\xfe" }, { 1008, "\xb6\x05\x95\x51\x4f\x24\xbc\x9f\xe5\x22\xa6\xca\xd7\x39\x36\x44" }, { 1024, "\xb5\x15\xa8\xc5\x01\x17\x54\xf5\x90\x03\x05\x8b\xdb\x81\x51\x4e" }, { 1520, "\x3c\x70\x04\x7e\x8c\xbc\x03\x8e\x3b\x98\x20\xdb\x60\x1d\xa4\x95" }, { 1536, "\x11\x75\xda\x6e\xe7\x56\xde\x46\xa5\x3e\x2b\x07\x56\x60\xb7\x70" }, { 2032, "\x00\xa5\x42\xbb\xa0\x21\x11\xcc\x2c\x65\xb3\x8e\xbd\xba\x58\x7e" }, { 2048, "\x58\x65\xfd\xbb\x5b\x48\x06\x41\x04\xe8\x30\xb3\x80\xf2\xae\xde" }, { 3056, "\x34\xb2\x1a\xd2\xad\x44\xe9\x99\xdb\x2d\x7f\x08\x63\xf0\xd9\xb6" }, { 3072, "\x84\xa9\x21\x8f\xc3\x6e\x8a\x5f\x2c\xcf\xbe\xae\x53\xa2\x7d\x25" }, { 4080, "\xa2\x22\x1a\x11\xb8\x33\xcc\xb4\x98\xa5\x95\x40\xf0\x54\x5f\x4a" }, { 4096, "\x5b\xbe\xb4\x78\x7d\x59\xe5\x37\x3f\xdb\xea\x6c\x6f\x75\xc2\x9b" } } }, | ||
| 104 | { "\xc1\x09\x16\x39\x08\xeb\xe5\x1d\xeb\xb4\x62\x27\xc6\xcc\x8b\x37\x64\x19\x10\x83\x32\x22\x77\x2a", 24, { { 0, "\x54\xb6\x4e\x6b\x5a\x20\xb5\xe2\xec\x84\x59\x3d\xc7\x98\x9d\xa7" }, { 16, "\xc1\x35\xee\xe2\x37\xa8\x54\x65\xff\x97\xdc\x03\x92\x4f\x45\xce" }, { 240, "\xcf\xcc\x92\x2f\xb4\xa1\x4a\xb4\x5d\x61\x75\xaa\xbb\xf2\xd2\x01" }, { 256, "\x83\x7b\x87\xe2\xa4\x46\xad\x0e\xf7\x98\xac\xd0\x2b\x94\x12\x4f" }, { 496, "\x17\xa6\xdb\xd6\x64\x92\x6a\x06\x36\xb3\xf4\xc3\x7a\x4f\x46\x94" }, { 512, "\x4a\x5f\x9f\x26\xae\xee\xd4\xd4\xa2\x5f\x63\x2d\x30\x52\x33\xd9" }, { 752, "\x80\xa3\xd0\x1e\xf0\x0c\x8e\x9a\x42\x09\xc1\x7f\x4e\xeb\x35\x8c" }, { 768, "\xd1\x5e\x7d\x5f\xfa\xaa\xbc\x02\x07\xbf\x20\x0a\x11\x77\x93\xa2" }, { 1008, "\x34\x96\x82\xbf\x58\x8e\xaa\x52\xd0\xaa\x15\x60\x34\x6a\xea\xfa" }, { 1024, "\xf5\x85\x4c\xdb\x76\xc8\x89\xe3\xad\x63\x35\x4e\x5f\x72\x75\xe3" }, { 1520, "\x53\x2c\x7c\xec\xcb\x39\xdf\x32\x36\x31\x84\x05\xa4\xb1\x27\x9c" }, { 1536, "\xba\xef\xe6\xd9\xce\xb6\x51\x84\x22\x60\xe0\xd1\xe0\x5e\x3b\x90" }, { 2032, "\xe8\x2d\x8c\x6d\xb5\x4e\x3c\x63\x3f\x58\x1c\x95\x2b\xa0\x42\x07" }, { 2048, "\x4b\x16\xe5\x0a\xbd\x38\x1b\xd7\x09\x00\xa9\xcd\x9a\x62\xcb\x23" }, { 3056, "\x36\x82\xee\x33\xbd\x14\x8b\xd9\xf5\x86\x56\xcd\x8f\x30\xd9\xfb" }, { 3072, "\x1e\x5a\x0b\x84\x75\x04\x5d\x9b\x20\xb2\x62\x86\x24\xed\xfd\x9e" }, { 4080, "\x63\xed\xd6\x84\xfb\x82\x62\x82\xfe\x52\x8f\x9c\x0e\x92\x37\xbc" }, { 4096, "\xe4\xdd\x2e\x98\xd6\x96\x0f\xae\x0b\x43\x54\x54\x56\x74\x33\x91" } } }, | ||
| 105 | { "\x1a\xda\x31\xd5\xcf\x68\x82\x21\xc1\x09\x16\x39\x08\xeb\xe5\x1d\xeb\xb4\x62\x27\xc6\xcc\x8b\x37\x64\x19\x10\x83\x32\x22\x77\x2a", 32, { { 0, "\xdd\x5b\xcb\x00\x18\xe9\x22\xd4\x94\x75\x9d\x7c\x39\x5d\x02\xd3" }, { 16, "\xc8\x44\x6f\x8f\x77\xab\xf7\x37\x68\x53\x53\xeb\x89\xa1\xc9\xeb" }, { 240, "\xaf\x3e\x30\xf9\xc0\x95\x04\x59\x38\x15\x15\x75\xc3\xfb\x90\x98" }, { 256, "\xf8\xcb\x62\x74\xdb\x99\xb8\x0b\x1d\x20\x12\xa9\x8e\xd4\x8f\x0e" }, { 496, "\x25\xc3\x00\x5a\x1c\xb8\x5d\xe0\x76\x25\x98\x39\xab\x71\x98\xab" }, { 512, "\x9d\xcb\xc1\x83\xe8\xcb\x99\x4b\x72\x7b\x75\xbe\x31\x80\x76\x9c" }, { 752, "\xa1\xd3\x07\x8d\xfa\x91\x69\x50\x3e\xd9\xd4\x49\x1d\xee\x4e\xb2" }, { 768, "\x85\x14\xa5\x49\x58\x58\x09\x6f\x59\x6e\x4b\xcd\x66\xb1\x06\x65" }, { 1008, "\x5f\x40\xd5\x9e\xc1\xb0\x3b\x33\x73\x8e\xfa\x60\xb2\x25\x5d\x31" }, { 1024, "\x34\x77\xc7\xf7\x64\xa4\x1b\xac\xef\xf9\x0b\xf1\x4f\x92\xb7\xcc" }, { 1520, "\xac\x4e\x95\x36\x8d\x99\xb9\xeb\x78\xb8\xda\x8f\x81\xff\xa7\x95" }, { 1536, "\x8c\x3c\x13\xf8\xc2\x38\x8b\xb7\x3f\x38\x57\x6e\x65\xb7\xc4\x46" }, { 2032, "\x13\xc4\xb9\xc1\xdf\xb6\x65\x79\xed\xdd\x8a\x28\x0b\x9f\x73\x16" }, { 2048, "\xdd\xd2\x78\x20\x55\x01\x26\x69\x8e\xfa\xad\xc6\x4b\x64\xf6\x6e" }, { 3056, "\xf0\x8f\x2e\x66\xd2\x8e\xd1\x43\xf3\xa2\x37\xcf\x9d\xe7\x35\x59" }, { 3072, "\x9e\xa3\x6c\x52\x55\x31\xb8\x80\xba\x12\x43\x34\xf5\x7b\x0b\x70" }, { 4080, "\xd5\xa3\x9e\x3d\xfc\xc5\x02\x80\xba\xc4\xa6\xb5\xaa\x0d\xca\x7d" }, { 4096, "\x37\x0b\x1c\x1f\xe6\x55\x91\x6d\x97\xfd\x0d\x47\xca\x1d\x72\xb8" } } } | ||
| 106 | }; | ||
| 107 | |||
| 108 | struct rc4_ctx ctx; | ||
| 109 | |||
| 110 | for ( size_t i = 0; i != NELEM(cases); ++i ) { | ||
| 111 | rc4_init(&ctx, cases[i].key, cases[i].sz); | ||
| 112 | |||
| 113 | unsigned int pos = 0; | ||
| 114 | |||
| 115 | for ( int j = 0; j != 18; ++j ) { | ||
| 116 | while ( pos != cases[i].test[j].pos ) { | ||
| 117 | rc4_get_byte(&ctx); | ||
| 118 | ++pos; | ||
| 119 | } | ||
| 120 | |||
| 121 | unsigned char bytes[16]; | ||
| 122 | for ( unsigned int k = 0; k != 16; ++k ) { | ||
| 123 | bytes[k] = rc4_get_byte(&ctx); | ||
| 124 | ++pos; | ||
| 125 | } | ||
| 126 | |||
| 127 | if ( memcmp(bytes, cases[i].test[j].bytes, 16) != 0 ) { | ||
| 128 | ERROR("Fehler"); | ||
| 129 | exit(EXIT_FAILURE); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | printf("Test #%zu : OK\n", i); | ||
| 134 | |||
| 135 | rc4_clear(&ctx); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | int | ||
| 140 | main() | ||
| 141 | { | ||
| 142 | rc4_test(); | ||
| 143 | |||
| 144 | struct random_ctx *random = rc4_create("\x01\x02\x03\x04\x05\x06\x07", 7); | ||
| 145 | |||
| 146 | for ( int j = 0; j != 18; ++j ) { | ||
| 147 | for ( int i = 0; i != 16; ++i ) { | ||
| 148 | printf("%02X ", random_get_byte(random)); | ||
| 149 | } | ||
| 150 | puts(""); | ||
| 151 | } | ||
| 152 | |||
| 153 | rc4_free(random); | ||
| 154 | |||
| 155 | return 0; | ||
| 156 | } | ||
diff --git a/src/ringbuff.c b/src/ringbuff.c new file mode 100644 index 0000000..1294b3b --- /dev/null +++ b/src/ringbuff.c | |||
| @@ -0,0 +1,156 @@ | |||
| 1 | #include <assert.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <stdlib.h> | ||
| 5 | |||
| 6 | #include "util.h" | ||
| 7 | |||
| 8 | /* --8<-- ring_type */ | ||
| 9 | typedef int T; | ||
| 10 | |||
| 11 | struct ring_buffer { | ||
| 12 | size_t head, tail; | ||
| 13 | T array[8]; /* fit for your needs... */ | ||
| 14 | }; | ||
| 15 | /* -->8-- */ | ||
| 16 | |||
| 17 | /* --8<-- ring_init */ | ||
| 18 | void | ||
| 19 | ring_init(struct ring_buffer *rb) | ||
| 20 | { | ||
| 21 | rb->head = rb->tail = 0; | ||
| 22 | } | ||
| 23 | /* -->8-- */ | ||
| 24 | |||
| 25 | /* --8<-- ring_push_front */ | ||
| 26 | bool | ||
| 27 | ring_push_front(struct ring_buffer *rb, T data) | ||
| 28 | { | ||
| 29 | const size_t prev = (rb->tail + NELEM(rb->array) - 1) % NELEM(rb->array); | ||
| 30 | |||
| 31 | if ( prev == rb->head ) { | ||
| 32 | return false; | ||
| 33 | } | ||
| 34 | |||
| 35 | rb->array[prev] = data; | ||
| 36 | rb->tail = prev; | ||
| 37 | |||
| 38 | return true; | ||
| 39 | } | ||
| 40 | /* -->8-- */ | ||
| 41 | |||
| 42 | /* --8<-- ring_push_back */ | ||
| 43 | bool | ||
| 44 | ring_push_back(struct ring_buffer *rb, T data) | ||
| 45 | { | ||
| 46 | const size_t next = (rb->head + 1) % NELEM(rb->array); | ||
| 47 | |||
| 48 | if ( next == rb->tail ) { | ||
| 49 | return false; | ||
| 50 | } | ||
| 51 | |||
| 52 | rb->array[rb->head] = data; | ||
| 53 | rb->head = next; | ||
| 54 | |||
| 55 | return true; | ||
| 56 | } | ||
| 57 | /* -->8-- */ | ||
| 58 | |||
| 59 | /* --8<-- ring_pop_front */ | ||
| 60 | bool | ||
| 61 | ring_pop_front(struct ring_buffer *rb, T *data) | ||
| 62 | { | ||
| 63 | if ( rb->head == rb->tail ) { | ||
| 64 | return false; | ||
| 65 | } | ||
| 66 | |||
| 67 | const size_t next = (rb->tail + 1) % NELEM(rb->array); | ||
| 68 | |||
| 69 | *data = rb->array[rb->tail]; | ||
| 70 | rb->tail = next; | ||
| 71 | |||
| 72 | return true; | ||
| 73 | } | ||
| 74 | /* -->8-- */ | ||
| 75 | |||
| 76 | /* --8<-- ring_pop_back */ | ||
| 77 | bool | ||
| 78 | ring_pop_back(struct ring_buffer *rb, T *data) | ||
| 79 | { | ||
| 80 | if ( rb->head == rb->tail ) { | ||
| 81 | return false; | ||
| 82 | } | ||
| 83 | |||
| 84 | const size_t prev = (rb->head + NELEM(rb->array) - 1) % NELEM(rb->array); | ||
| 85 | |||
| 86 | *data = rb->array[prev]; | ||
| 87 | rb->head = prev; | ||
| 88 | |||
| 89 | return true; | ||
| 90 | } | ||
| 91 | /* -->8-- */ | ||
| 92 | |||
| 93 | /* --8<-- ring_put */ | ||
| 94 | bool | ||
| 95 | ring_put(struct ring_buffer *rb, T data) | ||
| 96 | { | ||
| 97 | return ring_push_back(rb, data); | ||
| 98 | } | ||
| 99 | /* -->8-- */ | ||
| 100 | |||
| 101 | /* --8<-- ring_get */ | ||
| 102 | bool | ||
| 103 | ring_get(struct ring_buffer *rb, T *data) | ||
| 104 | { | ||
| 105 | return ring_pop_front(rb, data); | ||
| 106 | } | ||
| 107 | /* -->8-- */ | ||
| 108 | |||
| 109 | void | ||
| 110 | debug_print(const char *msg, struct ring_buffer *rb) | ||
| 111 | { | ||
| 112 | printf("%s: head: %zu, tail: %zu\n", msg, rb->head, rb->tail); | ||
| 113 | } | ||
| 114 | |||
| 115 | int | ||
| 116 | main(void) | ||
| 117 | { | ||
| 118 | #if 0 | ||
| 119 | struct ring_buffer rb; | ||
| 120 | ring_init(&rb); | ||
| 121 | #else | ||
| 122 | struct ring_buffer rb = { .head = 0, .tail = 0 }; | ||
| 123 | #endif | ||
| 124 | |||
| 125 | assert(ring_push_back(&rb, 1) == true); // 1 | ||
| 126 | assert(ring_push_back(&rb, 2) == true); // 1, 2 | ||
| 127 | assert(ring_push_back(&rb, 3) == true); // 1, 2, 3 | ||
| 128 | assert(ring_push_back(&rb, 4) == true); // 1, 2, 3, 4 | ||
| 129 | |||
| 130 | debug_print("Stand", &rb); | ||
| 131 | |||
| 132 | assert(ring_push_front(&rb, 0) == true); // 0, 1, 2, 3, 4 | ||
| 133 | assert(ring_push_front(&rb, -1) == true); // -1, 0, 1, 2, 3, 4 | ||
| 134 | |||
| 135 | debug_print("Stand", &rb); | ||
| 136 | |||
| 137 | T temp; | ||
| 138 | assert(ring_pop_back(&rb, &temp) == true); // -1, 0, 1, 2, 3 | ||
| 139 | assert(ring_pop_front(&rb, &temp) == true); // 0, 1, 2, 3 | ||
| 140 | |||
| 141 | debug_print("Stand", &rb); | ||
| 142 | |||
| 143 | assert(ring_push_back(&rb, 4) == true); // 0, 1, 2, 3, 4 | ||
| 144 | assert(ring_push_back(&rb, 5) == true); // 0, 1, 2, 3, 4, 5 | ||
| 145 | assert(ring_push_back(&rb, 6) == true); // 0, 1, 2, 3, 4, 5, 6 | ||
| 146 | assert(ring_push_back(&rb, 7) == false); // 0, 1, 2, 3, 4, 5, 6 | ||
| 147 | assert(ring_push_front(&rb, 7) == false); // 0, 1, 2, 3, 4, 5, 6 | ||
| 148 | |||
| 149 | while ( ring_pop_back(&rb, &temp) ) { | ||
| 150 | printf("temp: %d\n", temp); | ||
| 151 | } | ||
| 152 | |||
| 153 | debug_print("Stand", &rb); | ||
| 154 | |||
| 155 | return EXIT_SUCCESS; | ||
| 156 | } | ||
diff --git a/src/shellsort.c b/src/shellsort.c new file mode 100644 index 0000000..29e6bf8 --- /dev/null +++ b/src/shellsort.c | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <time.h> | ||
| 4 | |||
| 5 | #include "util.h" | ||
| 6 | |||
| 7 | typedef int T; | ||
| 8 | |||
| 9 | void | ||
| 10 | shellsort(T a[], size_t n) | ||
| 11 | { | ||
| 12 | //static const size_t gaps[] = { 701, 301, 132, 57, 23, 10, 4, 1 }; | ||
| 13 | |||
| 14 | // Wikipedia: | ||
| 15 | //static const size_t gaps[] = { 2147483647, 1131376761, 410151271, 157840433, 58548857, 21521774, 8810089, 3501671, 1355339, 543749, 213331, 84801, 27901, 11969, 4711, 1968, 815, 271, 111, 41, 13, 4, 1 }; | ||
| 16 | |||
| 17 | // https://www.cs.princeton.edu/~rs/shell/paperF.pdf | ||
| 18 | static const size_t gaps[] = { 1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1 }; | ||
| 19 | |||
| 20 | for ( size_t k = 0; k < NELEM(gaps); ++k ) { | ||
| 21 | const size_t gap = gaps[k]; | ||
| 22 | |||
| 23 | for ( size_t i = gap; i < n; i++ ) { | ||
| 24 | size_t j = i; | ||
| 25 | T temp = a[i]; | ||
| 26 | |||
| 27 | for ( ; j >= gap && a[j - gap] > temp; j -= gap ) | ||
| 28 | a[j] = a[j - gap]; | ||
| 29 | |||
| 30 | a[j] = temp; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | static void | ||
| 36 | test(T a[], size_t n) | ||
| 37 | { | ||
| 38 | for ( size_t i = 1; i < n; ++i ) { | ||
| 39 | if ( a[i - 1] > a[i] ) { | ||
| 40 | ERROR("sortierung passt nicht"); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | int | ||
| 46 | main(void) | ||
| 47 | { | ||
| 48 | T a[1000000]; | ||
| 49 | |||
| 50 | srand(time(NULL)); | ||
| 51 | for ( size_t i = 0; i != NELEM(a); ++i ) | ||
| 52 | a[i] = rand() % 1000; | ||
| 53 | |||
| 54 | clock_t start = clock(); | ||
| 55 | shellsort(a, NELEM(a)); | ||
| 56 | clock_t end = clock(); | ||
| 57 | |||
| 58 | test(a, NELEM(a)); | ||
| 59 | |||
| 60 | printf("duration: %.3f sec\n", ((double) (end - start)) / CLOCKS_PER_SEC); | ||
| 61 | |||
| 62 | return EXIT_SUCCESS; | ||
| 63 | } | ||
diff --git a/src/stack.c b/src/stack.c new file mode 100644 index 0000000..48b9eba --- /dev/null +++ b/src/stack.c | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | /* Standard C */ | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <stdlib.h> | ||
| 5 | |||
| 6 | /* Project */ | ||
| 7 | #include "util.h" | ||
| 8 | |||
| 9 | /* --8<-- stack_type */ | ||
| 10 | typedef int T; | ||
| 11 | |||
| 12 | struct stack_item { | ||
| 13 | struct stack_item *next; | ||
| 14 | T data; | ||
| 15 | }; | ||
| 16 | |||
| 17 | struct stack { | ||
| 18 | struct stack_item *head; | ||
| 19 | }; | ||
| 20 | /* -->8-- */ | ||
| 21 | |||
| 22 | /* --8<-- stack_init */ | ||
| 23 | void | ||
| 24 | stack_init(struct stack *stack) | ||
| 25 | { | ||
| 26 | stack->head = NULL; | ||
| 27 | } | ||
| 28 | /* -->8-- */ | ||
| 29 | |||
| 30 | /* --8<-- stack_push */ | ||
| 31 | void | ||
| 32 | stack_push(struct stack *stack, T data) | ||
| 33 | { | ||
| 34 | struct stack_item *new_item; | ||
| 35 | |||
| 36 | if ( (new_item = malloc(sizeof *new_item)) != NULL ) { | ||
| 37 | new_item->data = data; | ||
| 38 | new_item->next = stack->head; | ||
| 39 | stack->head = new_item; | ||
| 40 | } | ||
| 41 | else | ||
| 42 | ERROR("out of memory"); | ||
| 43 | } | ||
| 44 | /* -->8-- */ | ||
| 45 | |||
| 46 | /* --8<-- stack_pop */ | ||
| 47 | bool | ||
| 48 | stack_pop(struct stack *stack, T *data) | ||
| 49 | { | ||
| 50 | if ( stack->head ) { | ||
| 51 | struct stack_item *next = stack->head->next; | ||
| 52 | |||
| 53 | if ( data ) { | ||
| 54 | *data = stack->head->data; | ||
| 55 | } | ||
| 56 | free(stack->head); | ||
| 57 | stack->head = next; | ||
| 58 | |||
| 59 | return true; | ||
| 60 | } | ||
| 61 | else | ||
| 62 | return false; | ||
| 63 | } | ||
| 64 | /* -->8-- */ | ||
| 65 | |||
| 66 | /* --8<-- stack_empty */ | ||
| 67 | bool | ||
| 68 | stack_empty(struct stack *stack) | ||
| 69 | { | ||
| 70 | return stack->head == NULL; | ||
| 71 | } | ||
| 72 | /* -->8-- */ | ||
| 73 | |||
| 74 | /* --8<-- stack_free */ | ||
| 75 | void | ||
| 76 | stack_free(struct stack *stack) | ||
| 77 | { | ||
| 78 | struct stack_item *item, *next; | ||
| 79 | |||
| 80 | for ( item = stack->head; item; item = next ) { | ||
| 81 | next = item->next; | ||
| 82 | free(item); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | /* -->8-- */ | ||
| 86 | |||
| 87 | int | ||
| 88 | main() | ||
| 89 | { | ||
| 90 | struct stack stack[1]; | ||
| 91 | |||
| 92 | stack_init(stack); | ||
| 93 | |||
| 94 | for ( int i = 0; i != 10; ++i ) | ||
| 95 | stack_push(stack, i); | ||
| 96 | |||
| 97 | /* | ||
| 98 | while ( !stack_empty(stack) ) { | ||
| 99 | int i; | ||
| 100 | if ( stack_pop(stack, &i) ) | ||
| 101 | printf("%d\n", i); | ||
| 102 | else | ||
| 103 | ERROR("this shouldn't happen!"); | ||
| 104 | } | ||
| 105 | */ | ||
| 106 | |||
| 107 | stack_free(stack); | ||
| 108 | |||
| 109 | return EXIT_SUCCESS; | ||
| 110 | } | ||
diff --git a/src/stack2.c b/src/stack2.c new file mode 100644 index 0000000..5f4ba41 --- /dev/null +++ b/src/stack2.c | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | #include <stdbool.h> | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | |||
| 5 | #include "util.h" | ||
| 6 | |||
| 7 | /* --8<-- stack2_type */ | ||
| 8 | typedef int T; | ||
| 9 | |||
| 10 | struct stack { | ||
| 11 | T * array; | ||
| 12 | size_t sz, p; | ||
| 13 | }; | ||
| 14 | /* -->8-- */ | ||
| 15 | |||
| 16 | /* --8<-- stack2_init */ | ||
| 17 | void | ||
| 18 | stack_init(struct stack *stack) | ||
| 19 | { | ||
| 20 | stack->array = NULL; | ||
| 21 | stack->sz = 0; | ||
| 22 | stack->p = 0; | ||
| 23 | } | ||
| 24 | /* -->8-- */ | ||
| 25 | |||
| 26 | /* --8<-- stack2_push */ | ||
| 27 | bool | ||
| 28 | stack_push(struct stack *stack, T data) | ||
| 29 | { | ||
| 30 | if ( stack->array == NULL ) { | ||
| 31 | if ( (stack->array = malloc(10 * sizeof *stack->array)) != NULL ) { | ||
| 32 | stack->sz = 10; | ||
| 33 | stack->p = 0; | ||
| 34 | } | ||
| 35 | else { | ||
| 36 | ERROR("out of memory"); | ||
| 37 | return false; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | if ( stack->p == stack->sz ) { | ||
| 42 | size_t new_sz; | ||
| 43 | T * new_array; | ||
| 44 | |||
| 45 | if ( (new_array = realloc(stack->array, (new_sz = (stack->sz * 3 / 2)) * sizeof *stack->array)) != NULL ) { | ||
| 46 | stack->array = new_array; | ||
| 47 | stack->sz = new_sz; | ||
| 48 | } | ||
| 49 | else { | ||
| 50 | ERROR("out of memory"); | ||
| 51 | return false; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | stack->array[stack->p++] = data; | ||
| 56 | return true; | ||
| 57 | } | ||
| 58 | /* -->8-- */ | ||
| 59 | |||
| 60 | /* --8<-- stack2_pop */ | ||
| 61 | bool | ||
| 62 | stack_pop(struct stack *stack, T *data) | ||
| 63 | { | ||
| 64 | if ( stack->p != 0 ) { | ||
| 65 | --stack->p; | ||
| 66 | |||
| 67 | if ( data ) { | ||
| 68 | *data = stack->array[stack->p]; | ||
| 69 | } | ||
| 70 | return true; | ||
| 71 | } | ||
| 72 | else | ||
| 73 | return false; | ||
| 74 | } | ||
| 75 | /* -->8-- */ | ||
| 76 | |||
| 77 | /* --8<-- stack2_empty */ | ||
| 78 | bool | ||
| 79 | stack_empty(struct stack *stack) | ||
| 80 | { | ||
| 81 | return stack->p == 0; | ||
| 82 | } | ||
| 83 | /* -->8-- */ | ||
| 84 | |||
| 85 | /* --8<-- stack2_free */ | ||
| 86 | void | ||
| 87 | stack_free(struct stack *stack) | ||
| 88 | { | ||
| 89 | free(stack->array); | ||
| 90 | } | ||
| 91 | /* -->8-- */ | ||
| 92 | |||
| 93 | int | ||
| 94 | main() | ||
| 95 | { | ||
| 96 | struct stack stack[1]; | ||
| 97 | |||
| 98 | stack_init(stack); | ||
| 99 | |||
| 100 | for ( int i = 0; i != 20; ++i ) | ||
| 101 | stack_push(stack, i); | ||
| 102 | |||
| 103 | while ( !stack_empty(stack) ) { | ||
| 104 | int i; | ||
| 105 | |||
| 106 | if ( stack_pop(stack, &i) ) | ||
| 107 | printf("%d\n", i); | ||
| 108 | else | ||
| 109 | ERROR("this shouldn't happen!"); | ||
| 110 | } | ||
| 111 | |||
| 112 | stack_free(stack); | ||
| 113 | |||
| 114 | return EXIT_SUCCESS; | ||
| 115 | } | ||
diff --git a/src/tree.c b/src/tree.c new file mode 100644 index 0000000..93690e2 --- /dev/null +++ b/src/tree.c | |||
| @@ -0,0 +1,806 @@ | |||
| 1 | // Binary Search Tree | ||
| 2 | #include <limits.h> | ||
| 3 | #include <stdbool.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <time.h> | ||
| 7 | |||
| 8 | #include "util.h" | ||
| 9 | |||
| 10 | /* --8<-- tree_type */ | ||
| 11 | typedef int T; | ||
| 12 | |||
| 13 | struct tree_node { | ||
| 14 | struct tree_node *left, *right; | ||
| 15 | T key; | ||
| 16 | int count; /* collision counter */ | ||
| 17 | /* ggf. weitere Felder... */ | ||
| 18 | }; | ||
| 19 | /* -->8-- */ | ||
| 20 | |||
| 21 | /* --8<-- tree_isBst */ | ||
| 22 | static bool | ||
| 23 | tree_isBstUntil(struct tree_node *tree, T min, T max) | ||
| 24 | { | ||
| 25 | if ( tree == NULL ) | ||
| 26 | return true; | ||
| 27 | |||
| 28 | if ( tree->key < min || tree->key > max ) | ||
| 29 | return false; | ||
| 30 | |||
| 31 | return tree_isBstUntil(tree->left, min, tree->key - 1) && | ||
| 32 | tree_isBstUntil(tree->right, tree->key + 1, max); | ||
| 33 | } | ||
| 34 | |||
| 35 | bool | ||
| 36 | tree_isBst(struct tree_node *tree) | ||
| 37 | { | ||
| 38 | return tree_isBstUntil(tree, INT_MIN, INT_MAX); | ||
| 39 | } | ||
| 40 | /* -->8-- */ | ||
| 41 | |||
| 42 | /* --8<-- tree_insert */ | ||
| 43 | struct tree_node * | ||
| 44 | tree_insert(struct tree_node *tree, T key) | ||
| 45 | { | ||
| 46 | if ( tree == NULL ) { | ||
| 47 | tree = malloc(sizeof *tree); | ||
| 48 | if ( tree ) { | ||
| 49 | tree->key = key; | ||
| 50 | tree->count = 1; | ||
| 51 | tree->left = NULL; | ||
| 52 | tree->right = NULL; | ||
| 53 | } | ||
| 54 | else | ||
| 55 | ERROR("out of memory"); | ||
| 56 | } | ||
| 57 | else if ( key < tree->key ) | ||
| 58 | tree->left = tree_insert(tree->left, key); | ||
| 59 | else if ( key > tree->key ) | ||
| 60 | tree->right = tree_insert(tree->right, key); | ||
| 61 | else /* key == tree->key */ | ||
| 62 | tree->count++; /* handle collision */ | ||
| 63 | |||
| 64 | return tree; | ||
| 65 | } | ||
| 66 | /* -->8-- */ | ||
| 67 | |||
| 68 | /* --8<-- tree_insert_it */ | ||
| 69 | struct tree_node * | ||
| 70 | tree_insert_it(struct tree_node *tree, T key) | ||
| 71 | { | ||
| 72 | struct tree_node *parent = NULL; | ||
| 73 | |||
| 74 | for ( struct tree_node *curr = tree; curr; ) { | ||
| 75 | parent = curr; | ||
| 76 | |||
| 77 | if ( key < curr->key ) { | ||
| 78 | curr = curr->left; | ||
| 79 | } | ||
| 80 | else if ( key > curr->key ) { | ||
| 81 | curr = curr->right; | ||
| 82 | } | ||
| 83 | else { /* key == current->key */ | ||
| 84 | curr->count++; | ||
| 85 | return tree; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | struct tree_node *new_node; | ||
| 90 | |||
| 91 | new_node = malloc(sizeof *new_node); | ||
| 92 | if ( new_node ) { | ||
| 93 | new_node->key = key; | ||
| 94 | new_node->count = 1; | ||
| 95 | new_node->left = NULL; | ||
| 96 | new_node->right = NULL; | ||
| 97 | |||
| 98 | if ( parent == NULL ) { | ||
| 99 | tree = new_node; | ||
| 100 | } | ||
| 101 | else if ( key < parent->key ) { | ||
| 102 | parent->left = new_node; | ||
| 103 | } | ||
| 104 | else { | ||
| 105 | parent->right = new_node; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | else { | ||
| 109 | ERROR("out of memory"); | ||
| 110 | } | ||
| 111 | |||
| 112 | return tree; | ||
| 113 | } | ||
| 114 | /* -->8-- */ | ||
| 115 | |||
| 116 | /* --8<-- tree_detach_min */ | ||
| 117 | static struct tree_node * | ||
| 118 | tree_detach_min(struct tree_node **ptree) | ||
| 119 | { | ||
| 120 | struct tree_node *tree = *ptree; | ||
| 121 | |||
| 122 | if ( tree == NULL ) | ||
| 123 | return NULL; | ||
| 124 | else if ( tree->left ) | ||
| 125 | return tree_detach_min(&tree->left); | ||
| 126 | else { | ||
| 127 | *ptree = tree->right; | ||
| 128 | return tree; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | /* -->8-- */ | ||
| 132 | |||
| 133 | /* --8<-- tree_remove */ | ||
| 134 | struct tree_node * | ||
| 135 | tree_remove(struct tree_node *tree, T key) | ||
| 136 | { | ||
| 137 | if ( tree == NULL ) | ||
| 138 | return NULL; | ||
| 139 | |||
| 140 | if ( key < tree->key ) | ||
| 141 | tree->left = tree_remove(tree->left, key); | ||
| 142 | else if ( key > tree->key ) | ||
| 143 | tree->right = tree_remove(tree->right, key); | ||
| 144 | else { /* key == tree->key */ | ||
| 145 | if ( --tree->count == 0 ) { /* Handle Collision */ | ||
| 146 | struct tree_node *temp = tree; | ||
| 147 | |||
| 148 | if ( tree->left == NULL ) { | ||
| 149 | tree = tree->right; | ||
| 150 | } | ||
| 151 | else if ( tree->right == NULL ) { | ||
| 152 | tree = tree->left; | ||
| 153 | } | ||
| 154 | else { | ||
| 155 | struct tree_node *min = tree_detach_min(&tree->right); | ||
| 156 | |||
| 157 | min->left = tree->left; | ||
| 158 | min->right = tree->right; | ||
| 159 | |||
| 160 | tree = min; | ||
| 161 | } | ||
| 162 | |||
| 163 | free(temp); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | return tree; | ||
| 167 | } | ||
| 168 | /* -->8-- */ | ||
| 169 | |||
| 170 | /* --8<-- tree_clear */ | ||
| 171 | void | ||
| 172 | tree_clear(struct tree_node *tree) | ||
| 173 | { | ||
| 174 | if ( tree ) { | ||
| 175 | tree_clear(tree->left); | ||
| 176 | tree_clear(tree->right); | ||
| 177 | free(tree); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | /* -->8-- */ | ||
| 181 | |||
| 182 | /* --8<-- tree_lookup */ | ||
| 183 | struct tree_node * | ||
| 184 | tree_lookup(struct tree_node *tree, T key) | ||
| 185 | { | ||
| 186 | while ( tree ) | ||
| 187 | if ( key < tree->key ) | ||
| 188 | tree = tree->left; | ||
| 189 | else if ( key > tree->key ) | ||
| 190 | tree = tree->right; | ||
| 191 | else /* key == tree->key */ | ||
| 192 | break; | ||
| 193 | |||
| 194 | return tree; | ||
| 195 | } | ||
| 196 | /* -->8-- */ | ||
| 197 | |||
| 198 | /* --8<-- tree_minimum */ | ||
| 199 | struct tree_node * | ||
| 200 | tree_minimum(struct tree_node *tree) | ||
| 201 | { | ||
| 202 | if ( tree ) | ||
| 203 | while ( tree->left ) | ||
| 204 | tree = tree->left; | ||
| 205 | |||
| 206 | return tree; | ||
| 207 | } | ||
| 208 | /* -->8-- */ | ||
| 209 | |||
| 210 | /* --8<-- tree_maximum */ | ||
| 211 | struct tree_node * | ||
| 212 | tree_maximum(struct tree_node *tree) | ||
| 213 | { | ||
| 214 | if ( tree ) | ||
| 215 | while ( tree->right ) | ||
| 216 | tree = tree->right; | ||
| 217 | |||
| 218 | return tree; | ||
| 219 | } | ||
| 220 | /* -->8-- */ | ||
| 221 | |||
| 222 | /* --8<-- tree_height */ | ||
| 223 | size_t | ||
| 224 | tree_height(struct tree_node *tree) | ||
| 225 | { | ||
| 226 | if ( tree ) { | ||
| 227 | size_t hl = tree_height(tree->left); | ||
| 228 | size_t hr = tree_height(tree->right); | ||
| 229 | |||
| 230 | return ((hl > hr) ? hl : hr) + 1; | ||
| 231 | } | ||
| 232 | |||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | /* -->8-- */ | ||
| 236 | |||
| 237 | /* --8<-- tree_count */ | ||
| 238 | size_t | ||
| 239 | tree_count(struct tree_node *tree) | ||
| 240 | { | ||
| 241 | if ( tree ) | ||
| 242 | return tree_count(tree->left) + tree_count(tree->right) + 1; | ||
| 243 | |||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | /* -->8-- */ | ||
| 247 | |||
| 248 | /* --8<-- tree_copy */ | ||
| 249 | struct tree_node * | ||
| 250 | tree_copy(struct tree_node *tree) | ||
| 251 | { | ||
| 252 | if ( tree ) { | ||
| 253 | struct tree_node *new_node; | ||
| 254 | |||
| 255 | new_node = malloc(sizeof *new_node); | ||
| 256 | if ( new_node ) { | ||
| 257 | new_node->key = tree->key; | ||
| 258 | new_node->count = tree->count; | ||
| 259 | new_node->left = tree_copy(tree->left); | ||
| 260 | new_node->right = tree_copy(tree->right); | ||
| 261 | } | ||
| 262 | else { | ||
| 263 | ERROR("out of memory"); | ||
| 264 | } | ||
| 265 | |||
| 266 | return new_node; | ||
| 267 | } | ||
| 268 | return NULL; | ||
| 269 | } | ||
| 270 | /* -->8-- */ | ||
| 271 | |||
| 272 | /* --8<-- tree_isleaf */ | ||
| 273 | bool | ||
| 274 | tree_isleaf(struct tree_node *tree) | ||
| 275 | { | ||
| 276 | return tree->left == NULL && tree->right == NULL; | ||
| 277 | } | ||
| 278 | /* -->8-- */ | ||
| 279 | |||
| 280 | /* --8<-- tree_apply_preorder */ | ||
| 281 | void | ||
| 282 | tree_apply_preorder(struct tree_node *tree, void (*visit)(T key, void *cl), void *cl) | ||
| 283 | { | ||
| 284 | if ( tree ) { | ||
| 285 | visit(tree->key, cl); | ||
| 286 | tree_apply_preorder(tree->left, visit, cl); | ||
| 287 | tree_apply_preorder(tree->right, visit, cl); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | /* -->8-- */ | ||
| 291 | |||
| 292 | /* --8<-- tree_apply_inorder */ | ||
| 293 | void | ||
| 294 | tree_apply_inorder(struct tree_node *tree, void (*visit)(T key, void *cl), void *cl) | ||
| 295 | { | ||
| 296 | if ( tree ) { | ||
| 297 | tree_apply_inorder(tree->left, visit, cl); | ||
| 298 | visit(tree->key, cl); | ||
| 299 | tree_apply_inorder(tree->right, visit, cl); | ||
| 300 | } | ||
| 301 | } | ||
| 302 | /* -->8-- */ | ||
| 303 | |||
| 304 | /* --8<-- tree_apply_postorder */ | ||
| 305 | void | ||
| 306 | tree_apply_postorder(struct tree_node *tree, void (*visit)(T key, void *cl), void *cl) | ||
| 307 | { | ||
| 308 | if ( tree ) { | ||
| 309 | tree_apply_postorder(tree->left, visit, cl); | ||
| 310 | tree_apply_postorder(tree->right, visit, cl); | ||
| 311 | visit(tree->key, cl); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | /* -->8-- */ | ||
| 315 | |||
| 316 | /* ===== */ | ||
| 317 | |||
| 318 | /* --8<-- tree_stack_type */ | ||
| 319 | struct stack_item { | ||
| 320 | struct stack_item *next; | ||
| 321 | struct tree_node * data; | ||
| 322 | }; | ||
| 323 | |||
| 324 | struct stack { | ||
| 325 | struct stack_item *head; | ||
| 326 | }; | ||
| 327 | /* -->8-- */ | ||
| 328 | |||
| 329 | /* --8<-- tree_stack_init */ | ||
| 330 | static void | ||
| 331 | stack_init(struct stack *stack) | ||
| 332 | { | ||
| 333 | stack->head = NULL; | ||
| 334 | } | ||
| 335 | /* -->8-- */ | ||
| 336 | |||
| 337 | /* --8<-- tree_stack_push */ | ||
| 338 | static void | ||
| 339 | stack_push(struct stack *stack, struct tree_node *data) | ||
| 340 | { | ||
| 341 | struct stack_item *new_item; | ||
| 342 | |||
| 343 | if ( (new_item = malloc(sizeof *new_item)) ) { | ||
| 344 | new_item->data = data; | ||
| 345 | new_item->next = stack->head; | ||
| 346 | stack->head = new_item; | ||
| 347 | } | ||
| 348 | else | ||
| 349 | ERROR("out of memory"); | ||
| 350 | } | ||
| 351 | /* -->8-- */ | ||
| 352 | |||
| 353 | /* --8<-- tree_stack_pop */ | ||
| 354 | static bool | ||
| 355 | stack_pop(struct stack *stack, struct tree_node **data) | ||
| 356 | { | ||
| 357 | if ( stack->head ) { | ||
| 358 | struct stack_item *next; | ||
| 359 | |||
| 360 | next = stack->head->next; | ||
| 361 | *data = stack->head->data; | ||
| 362 | |||
| 363 | free(stack->head); | ||
| 364 | stack->head = next; | ||
| 365 | |||
| 366 | return true; | ||
| 367 | } | ||
| 368 | else | ||
| 369 | return false; | ||
| 370 | } | ||
| 371 | /* -->8-- */ | ||
| 372 | |||
| 373 | /* --8<-- tree_stack_peek */ | ||
| 374 | static struct tree_node * | ||
| 375 | stack_peek(struct stack *stack) | ||
| 376 | { | ||
| 377 | return (stack->head) ? stack->head->data : NULL; | ||
| 378 | } | ||
| 379 | /* -->8-- */ | ||
| 380 | |||
| 381 | /* --8<-- tree_stack_empty */ | ||
| 382 | static bool | ||
| 383 | stack_empty(struct stack *stack) | ||
| 384 | { | ||
| 385 | return stack->head == NULL; | ||
| 386 | } | ||
| 387 | /* -->8-- */ | ||
| 388 | |||
| 389 | /* --8<-- tree_stack_free */ | ||
| 390 | void | ||
| 391 | stack_free(struct stack *stack) | ||
| 392 | { | ||
| 393 | struct stack_item *item, *next; | ||
| 394 | |||
| 395 | for ( item = stack->head; item; item = next ) { | ||
| 396 | next = item->next; | ||
| 397 | free(item); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | /* -->8-- */ | ||
| 401 | |||
| 402 | /* ===== */ | ||
| 403 | |||
| 404 | /* --8<-- tree_queue_type */ | ||
| 405 | struct queue_item { | ||
| 406 | struct queue_item *next; | ||
| 407 | struct tree_node * data; | ||
| 408 | }; | ||
| 409 | |||
| 410 | struct queue { | ||
| 411 | struct queue_item *head, *tail; | ||
| 412 | }; | ||
| 413 | /* -->8-- */ | ||
| 414 | |||
| 415 | /* --8<-- tree_queue_init */ | ||
| 416 | void | ||
| 417 | queue_init(struct queue *queue) | ||
| 418 | { | ||
| 419 | queue->head = NULL; | ||
| 420 | } | ||
| 421 | /* -->8-- */ | ||
| 422 | |||
| 423 | /* --8<-- tree_queue_put */ | ||
| 424 | void | ||
| 425 | queue_put(struct queue *queue, struct tree_node *data) | ||
| 426 | { | ||
| 427 | struct queue_item *new_item; | ||
| 428 | |||
| 429 | if ( (new_item = malloc(sizeof *new_item)) ) { | ||
| 430 | struct queue_item *tail; | ||
| 431 | |||
| 432 | tail = queue->tail; | ||
| 433 | new_item->data = data; | ||
| 434 | new_item->next = NULL; | ||
| 435 | queue->tail = new_item; | ||
| 436 | |||
| 437 | if ( queue->head == NULL ) | ||
| 438 | queue->head = queue->tail; | ||
| 439 | else | ||
| 440 | tail->next = queue->tail; | ||
| 441 | } | ||
| 442 | else | ||
| 443 | ERROR("out of memory"); | ||
| 444 | } | ||
| 445 | /* -->8-- */ | ||
| 446 | |||
| 447 | /* --8<-- tree_queue_get */ | ||
| 448 | bool | ||
| 449 | queue_get(struct queue *queue, struct tree_node **data) | ||
| 450 | { | ||
| 451 | if ( queue->head ) { | ||
| 452 | struct queue_item *next; | ||
| 453 | |||
| 454 | next = queue->head->next; | ||
| 455 | *data = queue->head->data; | ||
| 456 | |||
| 457 | free(queue->head); | ||
| 458 | queue->head = next; | ||
| 459 | |||
| 460 | return true; | ||
| 461 | } | ||
| 462 | else | ||
| 463 | return false; | ||
| 464 | } | ||
| 465 | /* -->8-- */ | ||
| 466 | |||
| 467 | /* --8<-- tree_queue_empty */ | ||
| 468 | bool | ||
| 469 | queue_empty(struct queue *queue) | ||
| 470 | { | ||
| 471 | return queue->head == NULL; | ||
| 472 | } | ||
| 473 | /* -->8-- */ | ||
| 474 | |||
| 475 | /* --8<-- tree_queue_free */ | ||
| 476 | void | ||
| 477 | queue_free(struct queue *queue) | ||
| 478 | { | ||
| 479 | struct queue_item *item, *next; | ||
| 480 | |||
| 481 | for ( item = queue->head; item; item = next ) { | ||
| 482 | next = item->next; | ||
| 483 | free(item); | ||
| 484 | } | ||
| 485 | } | ||
| 486 | /* -->8-- */ | ||
| 487 | |||
| 488 | /* ===== */ | ||
| 489 | |||
| 490 | /* --8<-- tree_apply_preorder_it */ | ||
| 491 | void | ||
| 492 | tree_apply_preorder_it(struct tree_node *tree, void (*visit)(T key, void *cl), void *cl) | ||
| 493 | { | ||
| 494 | if ( tree ) { | ||
| 495 | struct stack stack; | ||
| 496 | |||
| 497 | stack_init(&stack); | ||
| 498 | |||
| 499 | stack_push(&stack, tree); | ||
| 500 | |||
| 501 | while ( stack_pop(&stack, &tree) ) { | ||
| 502 | visit(tree->key, cl); | ||
| 503 | |||
| 504 | if ( tree->right ) | ||
| 505 | stack_push(&stack, tree->right); | ||
| 506 | if ( tree->left ) | ||
| 507 | stack_push(&stack, tree->left); | ||
| 508 | } | ||
| 509 | |||
| 510 | stack_free(&stack); | ||
| 511 | } | ||
| 512 | } | ||
| 513 | /* -->8-- */ | ||
| 514 | |||
| 515 | /* --8<-- tree_apply_inorder_it */ | ||
| 516 | void | ||
| 517 | tree_apply_inorder_it(struct tree_node *tree, void (*visit)(T key, void *cl), void *cl) | ||
| 518 | { | ||
| 519 | if ( tree ) { | ||
| 520 | struct stack stack; | ||
| 521 | |||
| 522 | stack_init(&stack); | ||
| 523 | |||
| 524 | while ( !stack_empty(&stack) || tree ) { | ||
| 525 | if ( tree ) { | ||
| 526 | stack_push(&stack, tree); | ||
| 527 | tree = tree->left; | ||
| 528 | } | ||
| 529 | else { | ||
| 530 | stack_pop(&stack, &tree); | ||
| 531 | visit(tree->key, cl); | ||
| 532 | tree = tree->right; | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | stack_free(&stack); | ||
| 537 | } | ||
| 538 | } | ||
| 539 | /* -->8-- */ | ||
| 540 | |||
| 541 | // Hier eine Version für PostOrder-Iterativ: | ||
| 542 | // Quelle: https://stackoverflow.com/a/16092333 | ||
| 543 | |||
| 544 | /* --8<-- tree_apply_postorder_it */ | ||
| 545 | void | ||
| 546 | tree_apply_postorder_it(struct tree_node *tree, void (*visit)(T key, void *cl), void *cl) | ||
| 547 | { | ||
| 548 | if ( tree ) { | ||
| 549 | struct stack stack; | ||
| 550 | |||
| 551 | stack_init(&stack); | ||
| 552 | stack_push(&stack, tree); | ||
| 553 | |||
| 554 | while ( !stack_empty(&stack) ) { | ||
| 555 | struct tree_node *next = stack_peek(&stack); | ||
| 556 | |||
| 557 | bool finishedSubtrees = (next->left == tree || next->right == tree); | ||
| 558 | |||
| 559 | if ( finishedSubtrees || tree_isleaf(next) ) { | ||
| 560 | stack_pop(&stack, &next); | ||
| 561 | |||
| 562 | visit(next->key, cl); | ||
| 563 | |||
| 564 | tree = next; | ||
| 565 | } | ||
| 566 | else { | ||
| 567 | if ( next->right ) { | ||
| 568 | stack_push(&stack, next->right); | ||
| 569 | } | ||
| 570 | if ( next->left ) { | ||
| 571 | stack_push(&stack, next->left); | ||
| 572 | } | ||
| 573 | } | ||
| 574 | } | ||
| 575 | stack_free(&stack); | ||
| 576 | } | ||
| 577 | } | ||
| 578 | /* -->8-- */ | ||
| 579 | |||
| 580 | /* --8<-- tree_apply_levelorder_it */ | ||
| 581 | void | ||
| 582 | tree_apply_levelorder_it(struct tree_node *tree, void (*visit)(T key, void *cl), void *cl) | ||
| 583 | { | ||
| 584 | if ( tree ) { | ||
| 585 | struct queue queue; | ||
| 586 | |||
| 587 | queue_init(&queue); | ||
| 588 | |||
| 589 | queue_put(&queue, tree); | ||
| 590 | |||
| 591 | while ( queue_get(&queue, &tree) ) { | ||
| 592 | visit(tree->key, cl); | ||
| 593 | |||
| 594 | if ( tree->left ) | ||
| 595 | queue_put(&queue, tree->left); | ||
| 596 | if ( tree->right ) | ||
| 597 | queue_put(&queue, tree->right); | ||
| 598 | } | ||
| 599 | |||
| 600 | queue_free(&queue); | ||
| 601 | } | ||
| 602 | } | ||
| 603 | /* -->8-- */ | ||
| 604 | |||
| 605 | /* ======================== */ | ||
| 606 | |||
| 607 | /* --8<-- tree_iterator_type */ | ||
| 608 | struct tree_iterator { | ||
| 609 | struct stack stack; | ||
| 610 | }; | ||
| 611 | /* -->8-- */ | ||
| 612 | |||
| 613 | /* --8<-- tree_iterator_push_leftmost */ | ||
| 614 | static void | ||
| 615 | tree_iterator_push_leftmost(struct stack *stack, struct tree_node *node) | ||
| 616 | { | ||
| 617 | for ( ; node; node = node->left ) { | ||
| 618 | stack_push(stack, node); | ||
| 619 | } | ||
| 620 | } | ||
| 621 | /* -->8-- */ | ||
| 622 | |||
| 623 | /* --8<-- tree_iterator_next */ | ||
| 624 | struct tree_node * | ||
| 625 | tree_iterator_next(struct tree_iterator *it) | ||
| 626 | { | ||
| 627 | struct tree_node *node = NULL; | ||
| 628 | |||
| 629 | if ( stack_pop(&it->stack, &node) ) { | ||
| 630 | tree_iterator_push_leftmost(&it->stack, node->right); | ||
| 631 | } | ||
| 632 | |||
| 633 | return node; | ||
| 634 | } | ||
| 635 | /* -->8-- */ | ||
| 636 | |||
| 637 | /* --8<-- tree_iterator_first */ | ||
| 638 | struct tree_node * | ||
| 639 | tree_iterator_first(struct tree_iterator *it, struct tree_node *tree) | ||
| 640 | { | ||
| 641 | stack_init(&it->stack); | ||
| 642 | |||
| 643 | tree_iterator_push_leftmost(&it->stack, tree); | ||
| 644 | |||
| 645 | return tree_iterator_next(it); | ||
| 646 | } | ||
| 647 | /* -->8-- */ | ||
| 648 | |||
| 649 | /* --8<-- tree_iterator_free */ | ||
| 650 | void | ||
| 651 | tree_iterator_free(struct tree_iterator *it) | ||
| 652 | { | ||
| 653 | stack_free(&it->stack); | ||
| 654 | } | ||
| 655 | /* -->8-- */ | ||
| 656 | |||
| 657 | /* --8<-- tree_preorder_iterator_next */ | ||
| 658 | struct tree_node * | ||
| 659 | tree_preorder_iterator_next(struct tree_iterator *it) | ||
| 660 | { | ||
| 661 | struct tree_node *node = NULL; | ||
| 662 | |||
| 663 | if ( stack_pop(&it->stack, &node) ) { | ||
| 664 | if ( node->right ) { | ||
| 665 | stack_push(&it->stack, node->right); | ||
| 666 | } | ||
| 667 | if ( node->left ) { | ||
| 668 | stack_push(&it->stack, node->left); | ||
| 669 | } | ||
| 670 | } | ||
| 671 | |||
| 672 | return node; | ||
| 673 | } | ||
| 674 | /* -->8-- */ | ||
| 675 | |||
| 676 | /* --8<-- tree_preorder_iterator_first */ | ||
| 677 | struct tree_node * | ||
| 678 | tree_preorder_iterator_first(struct tree_iterator *it, struct tree_node *tree) | ||
| 679 | { | ||
| 680 | stack_init(&it->stack); | ||
| 681 | |||
| 682 | if ( tree ) { | ||
| 683 | stack_push(&it->stack, tree); | ||
| 684 | |||
| 685 | return tree_preorder_iterator_next(it); | ||
| 686 | } | ||
| 687 | else { | ||
| 688 | return NULL; | ||
| 689 | } | ||
| 690 | } | ||
| 691 | /* -->8-- */ | ||
| 692 | |||
| 693 | /* ===== */ | ||
| 694 | |||
| 695 | void | ||
| 696 | print(T data, void *cl) | ||
| 697 | { | ||
| 698 | (void) cl; | ||
| 699 | printf("%d\n", data); | ||
| 700 | } | ||
| 701 | |||
| 702 | #include "treeutil.h" | ||
| 703 | |||
| 704 | int | ||
| 705 | main_(void) | ||
| 706 | { | ||
| 707 | // Teste den Fall von mycodeschool | ||
| 708 | |||
| 709 | struct tree_node *tree = NULL; | ||
| 710 | |||
| 711 | tree = tree_insert(tree, 12); | ||
| 712 | tree = tree_insert(tree, 5); | ||
| 713 | tree = tree_insert(tree, 15); | ||
| 714 | tree = tree_insert(tree, 3); | ||
| 715 | tree = tree_insert(tree, 7); | ||
| 716 | tree = tree_insert(tree, 13); | ||
| 717 | tree = tree_insert(tree, 17); | ||
| 718 | tree = tree_insert(tree, 1); | ||
| 719 | tree = tree_insert(tree, 9); | ||
| 720 | tree = tree_insert(tree, 14); | ||
| 721 | tree = tree_insert(tree, 20); | ||
| 722 | tree = tree_insert(tree, 8); | ||
| 723 | tree = tree_insert(tree, 11); | ||
| 724 | tree = tree_insert(tree, 18); | ||
| 725 | |||
| 726 | tree = tree_remove(tree, 15); | ||
| 727 | |||
| 728 | if ( !tree_isBst(tree) ) { | ||
| 729 | fprintf(stderr, "Tree ist kein BST!!\n"); | ||
| 730 | return EXIT_FAILURE; | ||
| 731 | } | ||
| 732 | |||
| 733 | show_tree(tree, 0, 0); | ||
| 734 | |||
| 735 | tree_clear(tree); | ||
| 736 | |||
| 737 | return EXIT_SUCCESS; | ||
| 738 | } | ||
| 739 | |||
| 740 | int | ||
| 741 | main__(void) | ||
| 742 | { | ||
| 743 | struct tree_node *tree = NULL; | ||
| 744 | |||
| 745 | tree = tree_insert(tree, 5); | ||
| 746 | tree = tree_insert(tree, 3); | ||
| 747 | tree = tree_insert(tree, 7); | ||
| 748 | tree = tree_insert(tree, 2); | ||
| 749 | tree = tree_insert(tree, 4); | ||
| 750 | tree = tree_insert(tree, 6); | ||
| 751 | tree = tree_insert(tree, 8); | ||
| 752 | |||
| 753 | tree = tree_remove(tree, 2); | ||
| 754 | tree = tree_remove(tree, 3); | ||
| 755 | tree = tree_remove(tree, 5); | ||
| 756 | |||
| 757 | if ( !tree_isBst(tree) ) { | ||
| 758 | fprintf(stderr, "Tree ist kein BST!!\n"); | ||
| 759 | return EXIT_FAILURE; | ||
| 760 | } | ||
| 761 | |||
| 762 | show_tree(tree, 0, 0); | ||
| 763 | |||
| 764 | tree_clear(tree); | ||
| 765 | |||
| 766 | return EXIT_SUCCESS; | ||
| 767 | } | ||
| 768 | |||
| 769 | int | ||
| 770 | main(void) | ||
| 771 | { | ||
| 772 | struct tree_node *tree = NULL; | ||
| 773 | |||
| 774 | tree = tree_insert_it(tree, 10); | ||
| 775 | tree = tree_insert_it(tree, 5); | ||
| 776 | tree = tree_insert_it(tree, 20); | ||
| 777 | tree = tree_insert_it(tree, 1); | ||
| 778 | tree = tree_insert_it(tree, 7); | ||
| 779 | tree = tree_insert_it(tree, 15); | ||
| 780 | tree = tree_insert_it(tree, 18); | ||
| 781 | |||
| 782 | tree_apply_preorder(tree, print, NULL); | ||
| 783 | puts("postorder:"); | ||
| 784 | tree_apply_postorder(tree, print, NULL); | ||
| 785 | puts("postorder_it:"); | ||
| 786 | tree_apply_postorder_it(tree, print, NULL); | ||
| 787 | show_tree(tree, 0, 0); | ||
| 788 | |||
| 789 | puts("levelorder_it:"); | ||
| 790 | tree_apply_levelorder_it(tree, print, NULL); | ||
| 791 | |||
| 792 | show_tree(tree, 0, 0); | ||
| 793 | |||
| 794 | struct tree_iterator it; | ||
| 795 | struct tree_node * node = tree_preorder_iterator_first(&it, tree); | ||
| 796 | while ( node ) { | ||
| 797 | fprintf(stdout, "%d\n", node->key); | ||
| 798 | |||
| 799 | node = tree_preorder_iterator_next(&it); | ||
| 800 | } | ||
| 801 | tree_iterator_free(&it); | ||
| 802 | |||
| 803 | tree_clear(tree); | ||
| 804 | |||
| 805 | return EXIT_SUCCESS; | ||
| 806 | } | ||
diff --git a/src/treeutil.h b/src/treeutil.h new file mode 100644 index 0000000..76627c0 --- /dev/null +++ b/src/treeutil.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | // aux display and verification routines, helpful but not essential | ||
| 2 | struct trunk { | ||
| 3 | struct trunk *prev; | ||
| 4 | const char * str; | ||
| 5 | }; | ||
| 6 | |||
| 7 | static void | ||
| 8 | show_trunks(struct trunk *p) | ||
| 9 | { | ||
| 10 | if ( !p ) | ||
| 11 | return; | ||
| 12 | show_trunks(p->prev); | ||
| 13 | printf("%s", p->str); | ||
| 14 | } | ||
| 15 | |||
| 16 | // this is very haphazzard | ||
| 17 | static void | ||
| 18 | show_tree(struct tree_node *root, struct trunk *prev, int is_left) | ||
| 19 | { | ||
| 20 | if ( root == NULL ) | ||
| 21 | return; | ||
| 22 | |||
| 23 | struct trunk this_disp = { prev, " " }; | ||
| 24 | const char * prev_str = this_disp.str; | ||
| 25 | show_tree(root->right, &this_disp, 1); | ||
| 26 | |||
| 27 | if ( !prev ) | ||
| 28 | this_disp.str = "---"; | ||
| 29 | else if ( is_left ) { | ||
| 30 | this_disp.str = ".--"; | ||
| 31 | prev_str = " |"; | ||
| 32 | } | ||
| 33 | else { | ||
| 34 | this_disp.str = "`--"; | ||
| 35 | prev->str = prev_str; | ||
| 36 | } | ||
| 37 | |||
| 38 | show_trunks(&this_disp); | ||
| 39 | if ( root->key >= 'A' && root->key <= 'Z' ) | ||
| 40 | printf("%c\n", root->key); | ||
| 41 | else | ||
| 42 | printf("%d\n", root->key); | ||
| 43 | |||
| 44 | if ( prev ) | ||
| 45 | prev->str = prev_str; | ||
| 46 | this_disp.str = " |"; | ||
| 47 | |||
| 48 | show_tree(root->left, &this_disp, 0); | ||
| 49 | if ( !prev ) | ||
| 50 | puts(""); | ||
| 51 | } | ||
diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..7ede6fd --- /dev/null +++ b/src/util.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <stdarg.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | |||
| 7 | static void | ||
| 8 | error(const char *msg, ...) | ||
| 9 | { | ||
| 10 | va_list ap; | ||
| 11 | |||
| 12 | va_start(ap, msg); | ||
| 13 | fprintf(stderr, "Error: "); | ||
| 14 | vfprintf(stderr, msg, ap); | ||
| 15 | va_end(ap); | ||
| 16 | fprintf(stderr, "\n"); | ||
| 17 | exit(EXIT_FAILURE); | ||
| 18 | } | ||
| 19 | |||
| 20 | #define ERROR(msg) error(msg " in \"%s()\" (%s:%d)", __func__, __FILE__, __LINE__) | ||
| 21 | |||
| 22 | #ifndef NELEM | ||
| 23 | # define NELEM(x) (sizeof(x) / sizeof(x[0])) /* NOLINT */ | ||
| 24 | #endif | ||
