292 lines
5.8 KiB
C
292 lines
5.8 KiB
C
#include <strings.h>
|
|
#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;
|
|
}
|