#include #include "skiplist.h" #include "x.h" sl_node *_sl_create_node(int key, void *data) { sl_node *x = xmalloc(sizeof(sl_node)); x->key = key; x->data = data; x->next = x->prev = x->below = x->above = NULL; return x; } void sl_init(slist *sl) { sl_node *x = _sl_create_node(KEY_INF_MIN, NULL); sl_node *y = _sl_create_node(KEY_INF_MAX, NULL); x->next = y; y->prev = x; sl->topleft = x; sl->bottomleft = x; sl->topright = y; sl->bottomright = y; sl->maxlevel = 0; } void _sl_add_level(slist *sl) { sl_node *x = _sl_create_node(KEY_INF_MIN, NULL); sl_node *y = _sl_create_node(KEY_INF_MAX, NULL); x->next = y; y->prev = x; x->below = sl->topleft; y->below = sl->topright; sl->topleft->above = x; sl->topright->above = y; sl->topleft = x; sl->topright = y; ++sl->maxlevel; } void sl_free(slist *sl) { sl_node *foo; sl_node *x; sl_node *y; for (foo = sl->bottomleft; foo != NULL;) { x = foo; foo = foo->next; while (x != NULL) { y = x; x = x->above; free(y->data); free(y); } } } void _print_key(int key) { if (key == KEY_INF_MIN) { debug("-INF -> "); } else if (key == KEY_INF_MAX) { debug("+INF -> "); } else { debug("%d -> ", key); } } void _sl_println() { int i; for (i = 0; i < 79; ++i) { debug("-"); } debug("\n"); } void sl_print(const slist *sl) { sl_node *foo; sl_node *x; int level = sl->maxlevel; _sl_println(); for (foo = sl->topleft; foo != NULL; foo = foo->below, --level) { debug("level %d: ", level); for (x = foo; x != NULL; x = x->next) { _print_key(x->key); } debug("\n"); } _sl_println(); debug("from below to above:\n"); for (foo = sl->bottomleft; foo != NULL; foo = foo->next) { for (x = foo; x != NULL; x = x->above) { _print_key(x->key); } debug("\n"); } _sl_println(); } #define HEAD 1 #define TAIL 0 int _toss_coin(int maxlevel) { int i; int x; i = 0; while(1) { x = random() & 0x1; if (x == TAIL) { break; } ++i; /* inc level only by one at one iter */ if (i == maxlevel + 1) { break; } }; return i; } /* * Clean top levels with only INFINITY nodes until only one such * level exists. */ void _sl_clean_top(slist *sl) { sl_node *foo; for (foo = sl->topleft; foo->below != NULL; foo = foo->below) { if (foo->next->key == KEY_INF_MAX && foo->below->next->key == KEY_INF_MAX) { sl->topleft = foo->below; sl->topright = foo->below->next; sl->topleft->above = NULL; sl->topright->above = NULL; --sl->maxlevel; free(foo->data); free(foo->next); free(foo); debug("cleaned one level\n"); } } } int sl_add(slist *sl, int key, void *data) { sl_node *foo; sl_node *x; int i; int k; int level; sl_node **update; int res; if (key == KEY_INF_MIN || key == KEY_INF_MAX) { return SL_ADD_INV; } i = _toss_coin(sl->maxlevel); debug("toss coin result: %d\n", i); if (i >= sl->maxlevel) { /* add one more level */ _sl_add_level(sl); debug("added level\n"); } update = (sl_node **) xmalloc(sizeof(sl_node *) * (sl->maxlevel + 1)); bzero(update, sizeof(sl_node *) * (sl->maxlevel + 1)); level = sl->maxlevel; foo = sl->topleft; while (1) { while (key >= foo->next->key) { foo = foo->next; } if (foo->below == NULL) { break; } update[level--] = foo; foo = foo->below; } update[level] = foo; debug("search finished at key: %d\n", foo->key); debug("update list keys:\n"); for (k = 0; k <= sl->maxlevel; ++k) { if (update[k] != 0) { debug("%d\n", update[k]->key); } } debug("adding\n"); if (foo->key == key) { res = SL_ADD_SAME; debug("key exists\n"); do { foo->data = data; foo = foo->above; } while (foo != NULL); } else { res = SL_ADD_NEW; debug("new key\n"); while (level <= i) { x = _sl_create_node(key, data); x->next = update[level]->next; update[level]->next->prev = x; x->prev = update[level]; update[level]->next = x; if (level > 0) { x->below = update[level - 1]->next; update[level - 1]->next->above = x; } ++level; } } _sl_clean_top(sl); free(update); return res; } sl_node *sl_find(slist *sl, int key) { sl_node *foo; foo = sl->topleft; while (1) { while (key >= foo->next->key) { foo = foo->next; } if (foo->below == NULL) { break; } foo = foo->below; } if (foo->key != key) { foo = NULL; } return foo; } int sl_remove(slist *sl, int key) { sl_node *foo; sl_node *x; int result; foo = sl->topleft; while (1) { while (key >= foo->next->key) { foo = foo->next; } if (foo->below == NULL) { break; } foo = foo->below; } if (foo->key == key) { result = 1; while (foo != NULL) { foo->prev->next = foo->next; foo->next->prev = foo->prev; free(foo->data); x = foo; foo = foo->above; free(x); } _sl_clean_top(sl); } else { result = 0; } return result; }