erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

417 lines
12 KiB

//
// Created by fox on 2017/10/10.
// Skip Lists: A Probabilistic Alternative to Balanced Trees
// indexable skip list
// duplicated score and node
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include "skiplist.h"
#include <time.h>
// 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);
};