From 2a3093b9f339117c5aac7c3c38762507ee1c096b Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Sun, 4 Nov 2018 06:34:54 +0800 Subject: [PATCH] skiplist in c --- c-cpp/17_skiplist/skiplist.c | 214 +++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 c-cpp/17_skiplist/skiplist.c diff --git a/c-cpp/17_skiplist/skiplist.c b/c-cpp/17_skiplist/skiplist.c new file mode 100644 index 0000000..82621c5 --- /dev/null +++ b/c-cpp/17_skiplist/skiplist.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include + +// https://www.youtube.com/watch?v=2g9OSRKJuzM&t=17s + +#define MAX_LEVEL 15 + +struct node { + int val; + int max_level; + struct node *forward[MAX_LEVEL]; +}; + +struct skip_list { + struct node head; + int max_level; + int max_level_nodes; +}; + +void node_init(struct node* node) +{ + memset(node, 0, sizeof(struct node)); +} + +void skip_list_init(struct skip_list* sl) +{ + node_init(&sl->head); + sl->max_level = 0; + sl->max_level_nodes = 0; +} + +void random_init() +{ + static bool done = false; + + if (done) + return; + + srandom(time(NULL)); + done = true; +} + +int random_level(void) +{ + int i, level = 1; + + random_init(); + + for (i = 1; i < MAX_LEVEL; i++) + if (random() % 2 == 1) + level++; + + return level; +} + +void random_level_test() +{ + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); +} + +void insert(struct skip_list *sl, int val) +{ + int level = random_level(); + struct node *update[MAX_LEVEL]; + struct node *new, *p; + int i; + + new = (struct node*)malloc(sizeof(struct node)); + if (!new) + return; + + new->max_level = level; + new->val = val; + + for (int i = 0; i < MAX_LEVEL; i++) + update[i] = &sl->head; + + p = &sl->head; + for (i = level - 1; i >= 0; i--) { + while(p->forward[i] && p->forward[i]->val < val) + p = p->forward[i]; + + update[i] = p; + } + + for (i = 0; i < level; i++) { + new->forward[i] = update[i]->forward[i]; + update[i]->forward[i] = new; + } + + if (sl->max_level < level) { + sl->max_level = level; + sl->max_level_nodes = 1; + } else if (sl->max_level == level) + sl->max_level_nodes++; +} + +struct node *find(struct skip_list* sl, int val) +{ + struct node *node = &sl->head; + int i; + + for (i = sl->max_level - 1; i >= 0; i--) { + while (node->forward[i] && node->forward[i]->val < val) + node = node->forward[i]; + } + + if (node->forward[0] && node->forward[0]->val == val) { + return node->forward[0]; + } + else + return NULL; +} + +void delete(struct skip_list* sl, int val) +{ + struct node *update[MAX_LEVEL]; + struct node *p; + int i; + + p = &sl->head; + + for (i = sl->max_level; i >= 0; i--) { + while (p->forward[i] && p->forward[i]->val < val) + p = p->forward[i]; + + update[i] = p; + } + + if (p->forward[0] == NULL || p->forward[0]->val != val) + return; + + if (p->forward[0]->max_level == sl->max_level) + sl->max_level_nodes--; + + for (i = sl->max_level-1; i >= 0; i--) { + if (update[i]->forward[i] && update[i]->forward[i]->val == val) + update[i]->forward[i] = update[i]->forward[i]->forward[i]; + } + + // fixup max_level and max_level_nodes + if (sl->max_level_nodes == 0) { + //sl->max_level--; + p = &sl->head; + // skip (max_level - 1), direct test (max_level - 2) + // since no nodes on (max_level - 1) + for (i = sl->max_level - 2; i >= 0; i--) { + while (p->forward[i]) { + sl->max_level_nodes++; + p = p->forward[i]; + } + + if (sl->max_level_nodes) { + sl->max_level = i + 1; + break; + } else + sl->max_level = i; + } + } +} + + +void print_sl(struct skip_list* sl) +{ + struct node *node; + int level; + + printf("%d level skip list with %d nodes on top\n", + sl->max_level, sl->max_level_nodes); + + for (level = sl->max_level - 1; level >= 0; level--) { + node = &sl->head; + printf("Level[%02d]:", level); + while (node->forward[level]) { + printf("%4d", node->forward[level]->val); + node = node->forward[level]; + } + printf("\n"); + } +} + +int main() +{ + struct skip_list sl; + struct node *node = NULL; + int i; + + skip_list_init(&sl); + print_sl(&sl); + + for (i = 0; i < 10; i++) + insert(&sl, i); + print_sl(&sl); + + node = find(&sl, 8); + if (node) + printf("find 8 in sl %d\n", node->val); + else + printf("8 not in sl\n"); + + for (i = 0; i < 10; i++) { + delete(&sl, i); + print_sl(&sl); + } + + return 0; +}