// // Created by fox on 2017/10/10. // Skip Lists: A Probabilistic Alternative to Balanced Trees // indexable skip list // duplicated score and node #include #include #include #include #include "skiplist.h" #include // from 0 to n #define SKIPLIST_MAX_LEVEL 15 #define LEVEL_SIZE (SKIPLIST_MAX_LEVEL+1) #define RAND_UNIFORM(x) (int)((double)rand() / RAND_MAX * (x)) /* Create a skiplist node with the specified number of levels. */ snode *skiplistCreateNode(int level, int score, vtype value) { snode *zn = (snode *)icalloc(sizeof(*zn)+level*sizeof(struct skiplistLevel)); zn->score = score; zn->value = value; return zn; } skiplist *skiplist_init(void) { time_t t; srand((unsigned)(time(&t))); snode *header = skiplistCreateNode(LEVEL_SIZE, INT_MAX, INT_MAX); for (int i = 0; i < LEVEL_SIZE; ++i) { header->level[i].span = 1; } skiplist *list = (skiplist *)imalloc(sizeof(skiplist)); list->header = header; list->level = 0; list->size = 0; return list; } static int rand_level() { int level = 0; while (rand() < RAND_MAX / 2 && level < SKIPLIST_MAX_LEVEL) // while (arc4random() < INT_MAX && level < SKIPLIST_MAX_LEVEL) level++; return level; } // insert score,node into a skiplist, return 0 int skiplist_insert(skiplist *list, int score, vtype value) { snode **update = (snode **)imalloc(sizeof(snode*) * (list->level + 1)); unsigned int *fore_width = (unsigned int *)imalloc(sizeof(unsigned int) * (list->level + 1)); snode *x = list->header; int i; for (i = list->level; i >= 0; i--) { fore_width[i] = 0; while (x->level[i].forward && x->level[i].forward->score <= score) { fore_width[i] += x->level[i].span; x = x->level[i].forward; } update[i] = x; } // assert(x->score <= score); int level = rand_level(); list->size = list->size+1; x = skiplistCreateNode(level+1, score, value); // the lowest layer is one by one x->level[0].forward = update[0]->level[0].forward; x->level[0].span = 1; update[0]->level[0].forward = x; unsigned int temp_width; for (i = 1; i <= (list->level < level ? list->level : level); i++) { temp_width = fore_width[i-1] + update[i-1]->level[i-1].span; x->level[i].forward = update[i]->level[i].forward; x->level[i].span = update[i]->level[i].span + 1 - temp_width; update[i]->level[i].forward = x; update[i]->level[i].span = temp_width; } if (level > list->level) { // complete the new level temp_width = fore_width[list->level] + update[list->level]->level[list->level].span; for (i = list->level+1; i <= level; i++) { list->header->level[i].span = temp_width; list->header->level[i].forward = x; x->level[i].forward = NULL; x->level[i].span = list->size + 1 - temp_width; } list->level = level; } else { // complete the unreached level for (; i <= list->level; ++i) { update[i]->level[i].span++; } } ifree(update); ifree(fore_width); return 0; } int skiplist_update(skiplist *list, int score, vtype value, int old_score) { skiplist_delete(list, old_score, value); return skiplist_insert(list, score, value); } // search score in skiplist. // set the struct with index and first node if exists, otherwise set index 0 void skiplist_search(skiplist *list, int score, skiplist_search_ret *ret) { snode *x = list->header; int temp_width = 1; for (int i = list->level; i >= 0; i--) { while (x->level[i].forward && x->level[i].forward->score < score) { temp_width += x->level[i].span; x = x->level[i].forward; } } x = x->level[0].forward; ret->index = temp_width; ret->node = x; } // first index of score int skiplist_index_of_score(skiplist *list, int score) { snode *x = list->header; int temp_width = 1; for (int i = list->level; i >= 0; i--) { while (x->level[i].forward && x->level[i].forward->score < score) { temp_width += x->level[i].span; x = x->level[i].forward; } } x = x->level[0].forward; // check if existed score if (x && x->score == score) { return temp_width; } return 0; } // search skiplist by index. Return the node if exists, otherwise NULL snode *skiplist_at(skiplist *list, int index) { snode *x = list->header; for (int i = list->level; i >= 0; i--) { while (x->level[i].forward) { if (x->level[i].span == index) { return x->level[i].forward; } if (x->level[i].span < index) { index -= x->level[i].span; x = x->level[i].forward; } else { break; } } } return NULL; } static void skiplist_node_free(snode *x) { if (x) { ifree(x); } } // delete by score,node. Return 0 if success, 1 if fail. int skiplist_delete(skiplist *list, int score, vtype value) { int i; snode **update = (snode **)imalloc(sizeof(snode*) * (list->level + 1)); snode *x = list->header; // find every level before the specified node for (i = list->level; i >= 0; --i) { while (1) { if (!(x->level[i].forward) || x->level[i].forward->score > score) { update[i] = x; break; } if (x->level[i].forward->score < score) { x = x->level[i].forward; continue; } // find the first node with same score int j; update[i] = x; for (j = i-1; j >= 0; --j) { while (x->level[j].forward->score < score) x = x->level[j].forward; update[j] = x; } x = x->level[0].forward; snode *x_start_search = x; // find the first node with same score and node while (x && x->value != value && x->score == score) { x = x->level[0].forward; } if (x && x->score == score) { // now x is the node to find // find nodes for every level before the node to find if (x == x_start_search) { // done i = 0; break; } // j is used to judge if change the x_start_search j = 0; snode *iter; for (; i >= 0; --i) { if (j) { update[i] = x_start_search; iter = x_start_search->level[0].forward; } else{ iter = x_start_search; } while (iter != x) { if (iter == update[i]->level[i].forward) { j = 1; x_start_search = iter; iter = iter->level[0].forward; update[i] = update[i]->level[i].forward; continue; } iter = iter->level[0].forward; } } i = 0; break; } else { // not found the node ifree(update); return 1; } } } if (x->score != score) { // not found the node ifree(update); return 1; } for (i = 0; i <= list->level && update[i]->level[i].forward == x; i++) { update[i]->level[i].forward = x->level[i].forward; update[i]->level[i].span += x->level[i].span - 1; } for (; i <= list->level; i++) { --(update[i]->level[i].span); } skiplist_node_free(x); while (list->level > 0 && list->header->level[list->level].forward == NULL) list->level--; list->size--; ifree(update); return 0; } // ifree the skiplist void skiplist_free(skiplist *list) { snode *current_node = list->header->level[0].forward; while(current_node != NULL) { snode *next_node = current_node->level[0].forward; skiplist_node_free(current_node); current_node = next_node; } ifree(list); } // print the skip list, just for test. static void skiplist_dump(skiplist *list) { int *width = (int *)imalloc(sizeof(int) * (list->level + 1) * list->size); memset(width, 0, sizeof(int) * (list->level + 1) * list->size); snode **tempn = (snode **)imalloc(sizeof(snode*) * (list->level + 1)); int i = 0, j; snode *x = list->header->level[0].forward; for (j = 0; j <= list->level; ++j) { tempn[j] = list->header->level[j].forward; } while (tempn[0] != NULL) { for (j = 1; j <= list->level; ++j) { if (tempn[j] == tempn[0]) { width[list->size * j + i] = tempn[j]->level[j].span; tempn[j] = tempn[j]->level[j].forward; } else { break; } } tempn[0] = tempn[0]->level[0].forward; ++i; } for (j = list->level; j > 0; --j) { for (i = 0; i < list->size; ++i) { if (width[j * list->size + i] == 0) printf(" "); else printf("%d ", width[j * list->size + i]); } printf("\n"); } while (x != NULL) { printf("%d:%d->", x->score, x->value); x = x->level[0].forward; } printf("NIL\n"); ifree(width); ifree(tempn); } void test_skiplist(void) { time_t t; srand((unsigned)(time(&t))); int arr[][2] = { {3, 1}, {3,2}, {6,6}, {9,9}, {3, 3}, {1, 1}, {4, 4}, {8, 8}, {7, 7}, {5,5}}, i; // int arr[] = { 3, 6, 9}, i; skiplist_search_ret tempx; skiplist *list = skiplist_init(); printf("search empty:--------------------\n"); skiplist_search(list, 5, &tempx); if (tempx.index > 0) { printf("error, found not existed item!\n"); } printf("delete empty:--------------------\n"); skiplist_delete(list, 5, 2); printf("Insert:--------------------\n"); for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { skiplist_insert(list, arr[i][0], arr[i][1]); } skiplist_dump(list); printf("search empty:--------------------\n"); skiplist_search(list, 5, &tempx); printf("index = %d\n", tempx.index); printf("Search by index:-----------\n"); int indexes[] = { 11, 3, 10 }; for (i = 0; i < sizeof(indexes) / sizeof(indexes[0]); i++) { snode *tempnode = skiplist_at(list, indexes[i]); if (tempnode) { printf("index = %d, score = %d, value = %d\n", indexes[i], tempnode->score, tempnode->value); } else { printf("no index = %d\n", indexes[i]); } } printf("Delete:--------------------\n"); skiplist_delete(list, 3, 2); skiplist_delete(list, 3, 1); skiplist_delete(list, 6, 6); skiplist_dump(list); clock_t start, finish; start = clock(); for (i = 0; i < 30*1000; ++i) { if (rand() < RAND_MAX / 5 * 3) { skiplist_insert(list, RAND_UNIFORM(100), RAND_UNIFORM(20)); } else { skiplist_delete(list, RAND_UNIFORM(100), RAND_UNIFORM(20)); } } finish = clock(); double duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%f seconds\n", duration ); printf("Search:--------------------\n"); int keys[] = { 0, 3, 7, 100, 11 }; for (i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { printf("index = %d, score = %d\n", skiplist_index_of_score(list, keys[i]), keys[i]); } skiplist_free(list); };