diff --git a/skiplist.c b/skiplist.c new file mode 100644 index 0000000..af37232 --- /dev/null +++ b/skiplist.c @@ -0,0 +1,296 @@ +#include +#include "skiplist.h" + +struct skiplist_t{ + skiplist_node_t* header; + skiplist_size_t size; + int level; + skiplist_probability_t probability; + skiplist_cmp cmp; +}; +#define SKIPLIST_LEVEL_MAX 32 +struct skiplist_level_t{ + skiplist_node_t* next; +}; +struct skiplist_node_t{ + void* data; + skiplist_node_t* prev; + skiplist_level_t lev[]; +}; +static inline skiplist_node_t* __skiplist_node_create(int level){ + return (skiplist_node_t*)SKIPLIST_ALLOC_MEM(sizeof(skiplist_node_t) + sizeof(skiplist_level_t) * level); +} +static inline void __skiplist_node_destroy(skiplist_node_t* node){ + SKIPLIST_FREE_MEM(node); +} +static inline int __skiplist_random_level(skiplist_t* sl){ + int level = 1; + while(SKIPLIST_RAND() >= (RAND_MAX * sl->probability)){ + ++ level; + } + return (level > SKIPLIST_LEVEL_MAX ? SKIPLIST_LEVEL_MAX : level); +} +static inline int +__skiplist_create( + skiplist_t** sl, + skiplist_probability_t probability, + skiplist_cmp cmp +){ + skiplist_t* tsl = (skiplist_t*)SKIPLIST_ALLOC_MEM(sizeof(skiplist_t)); + if(tsl == NULL){ + *sl = tsl; + return SKIPLISTERR_POINTR; + } + if((tsl->header = __skiplist_node_create(SKIPLIST_LEVEL_MAX)) == NULL){ + *sl = NULL; + SKIPLIST_FREE_MEM(tsl); + return SKIPLISTERR_POINTR; + } + tsl->header->prev = tsl->header; + int i = 0; + for(;i < SKIPLIST_LEVEL_MAX; ++i){ + tsl->header->lev[i].next = tsl->header; + } + tsl->size = 0; + tsl->level = 1; + tsl->probability = probability; + tsl->cmp = cmp; + *sl = tsl; + return SKIPLISTOK; +} +static inline int +__skiplist_insert( + skiplist_t* sl, + void* key, + void* data +){ + skiplist_node_t* level_prev[SKIPLIST_LEVEL_MAX]; + skiplist_node_t *cur = sl->header,*end = sl->header; + skiplist_node_t* node; + int i = sl->level - 1,level; + for(;i >= 0; -- i){ + for(;cur->lev[i].next != end && sl->cmp(key,cur->lev[i].next->data) > 0;cur = cur->lev[i].next); + level_prev[i] = cur; + } + if(cur->lev[0].next != end && sl->cmp(key,cur->lev[0].next->data) == 0){ + return SKIPLISTERR_REEXIST; + } + level = __skiplist_random_level(sl); + if((node = __skiplist_node_create(level)) == NULL){ + return SKIPLISTERR_POINTR; + } + node->data = data; + if(level > sl->level){ + for(i = sl->level;i < level; ++ i){ + level_prev[i] = sl->header; + } + sl->level = level; + } + for(i = 0;i < level; ++ i){ + node->lev[i].next = level_prev[i]->lev[i].next; + level_prev[i]->lev[i].next = node; + } + node->prev = level_prev[0]; + node->lev[0].next->prev = node; + ++ sl->size; + return SKIPLISTOK; +} +static inline int +__skiplist_erase( + skiplist_t* sl, + void* key, + void** retdata +){ + skiplist_node_t* level_prev[SKIPLIST_LEVEL_MAX]; + skiplist_node_t *cur = sl->header,*end = sl->header; + skiplist_node_t* node; + int i = sl->level - 1; + for(;i >= 0; -- i){ + for(;cur->lev[i].next != end && sl->cmp(key,cur->lev[i].next->data) > 0;cur = cur->lev[i].next); + level_prev[i] = cur; + } + if(cur->lev[0].next == end || sl->cmp(key,cur->lev[0].next->data) < 0){ + return SKIPLISTERR_NOEXIST; + } + cur = cur->lev[0].next; + node = cur; + for(i = 0;i < sl->level; ++i){ + if(level_prev[i]->lev[i].next == node){ + level_prev[i]->lev[i].next = node->lev[i].next; + } + } + node->lev[0].next->prev = node->prev; + for(;sl->level > 1 && sl->header->lev[sl->level - 1].next == end; -- sl->level); + if(retdata != NULL){ + *retdata = node->data; + } + __skiplist_node_destroy(node); + -- sl->size; + return SKIPLISTOK; +} +static inline int +__skiplist_exist( + skiplist_t* sl, + void* key, + void** retdata +){ + skiplist_node_t *cur = sl->header,*end = sl->header; + int i = sl->level - 1; + for(;i >= 0; -- i){ + for(;cur->lev[i].next != end && sl->cmp(key,cur->lev[i].next->data) > 0;cur = cur->lev[i].next); + } + if(cur->lev[0].next != end && sl->cmp(key,cur->lev[0].next->data) == 0){ + if(retdata != NULL){ + *retdata = cur->lev[0].next->data; + } + return SKIPLISTOK_EXIST; + } + return SKIPLISTERR_NOEXIST; +} +static inline int +__skiplist_update( + skiplist_t* sl, + void* oldkey, + void* newkey, + void* newdata, + void** retdata +){ + skiplist_node_t* level_prev[SKIPLIST_LEVEL_MAX]; + skiplist_node_t *cur = sl->header,*node,*end = sl->header; + int i = sl->level - 1; + for(;i >= 0; -- i){ + for(;cur->lev[i].next != end && sl->cmp(oldkey,cur->lev[i].next->data) > 0;cur = cur->lev[i].next); + level_prev[i] = cur; + } + if(cur->lev[0].next != end && sl->cmp(oldkey,cur->lev[0].next->data) == 0){ + cur = cur->lev[0].next; + if((cur->prev != end && sl->cmp(newkey,cur->prev->data) == 0) || + (cur->lev[0].next != end && sl->cmp(newkey,cur->lev[0].next->data) == 0)){ + return SKIPLISTERR_REEXIST; + } + if(sl->cmp(newkey,cur->data) == 0){ + if(retdata != NULL){ + *retdata = cur->data; + } + cur->data = newdata; + } + else{ + node = cur; + for(i = 0;i < sl->level; ++ i){ + if(level_prev[i]->lev[i].next == node){ + level_prev[i]->lev[i].next = node->lev[i].next; + } + } + node->lev[0].next->prev = node->prev; + for(;sl->level > 1 && sl->header->lev[sl->level - 1].next == end; -- sl->level); + if(retdata != NULL){ + *retdata = node->data; + } + __skiplist_node_destroy(node); + -- sl->size; + return __skiplist_insert(sl,newkey,newdata); + } + return SKIPLISTOK; + } + return SKIPLISTERR_NOEXIST; +} + +int skiplist_create(skiplist_t** sl,skiplist_probability_t probability,skiplist_cmp cmp){ + if(sl == NULL || probability <= 1e-6 || probability - 1 >= 1e-6 || cmp == NULL){ + return SKIPLISTERR_PARAM; + } + return __skiplist_create(sl,probability,cmp); +} +int skiplist_size(skiplist_t* sl,skiplist_size_t* size){ + if(sl == NULL || size == NULL){ + *size = 0; + return SKIPLISTERR_PARAM; + } + *size = sl->size; + return SKIPLISTOK; +} +int skiplist_getcmp(skiplist_t* sl,skiplist_cmp* cmp){ + if(sl == NULL || cmp == NULL){ + return SKIPLISTERR_PARAM; + } + *cmp = sl->cmp; + return SKIPLISTOK; +} +int skiplist_insert(skiplist_t* sl,void* key,void* data){ + if(sl == NULL || key == NULL || data == NULL){ + return SKIPLISTERR_PARAM; + } + return __skiplist_insert(sl,key,data); +} +int skiplist_erase(skiplist_t* sl,void* key,void** retdata){ + if(sl == NULL || key == NULL){ + return SKIPLISTERR_PARAM; + } + return __skiplist_erase(sl,key,retdata); +} +int skiplist_exist(skiplist_t* sl,void* key,void** retdata){ + if(sl == NULL || key == NULL){ + return SKIPLISTERR_PARAM; + } + return __skiplist_exist(sl,key,retdata); +} +int skiplist_update(skiplist_t* sl,void* oldkey,void* newkey,void* newdata,void** retdata){ + if(sl == NULL || oldkey == NULL || newkey == NULL || newdata == NULL){ + return SKIPLISTERR_PARAM; + } + return __skiplist_update(sl,oldkey,newkey,newdata,retdata); +} +int skiplist_destroy(skiplist_t** sl){ + if(sl == NULL || *sl == NULL){ + return SKIPLISTERR_PARAM; + } + skiplist_node_t *cur = (*sl)->header,*tmp,*end = (*sl)->header; + for( ;cur != end; cur = tmp){ + tmp = cur->lev[0].next; + __skiplist_node_destroy(cur); + } + SKIPLIST_FREE_MEM(*sl); + *sl = NULL; + return SKIPLISTOK; +} +int skiplist_begin(skiplist_t* sl,skiplist_iterator_t* it){ + int ret = SKIPLISTERR_PARAM; + if(sl == NULL || it == NULL){ + return ret; + } + if((ret = skiplist_iterator_create(it)) == SKIPLISTOK){ + *it = sl->header->lev[0].next; + } + return ret; +} +int skiplist_end(skiplist_t* sl,skiplist_iterator_t* it){ + int ret = SKIPLISTERR_PARAM; + if(sl == NULL || it == NULL){ + return ret; + } + if((ret = skiplist_iterator_create(it)) == SKIPLISTOK){ + *it = sl->header; + } + return ret; +} +int skiplist_iterator_create(skiplist_iterator_t* it){ + return SKIPLISTOK; +} +int skiplist_iterator_equal(skiplist_iterator_t* it1,skiplist_iterator_t* it2){ + return ((*it1) == (*it2)); +} +void skiplist_iterator_assign(skiplist_iterator_t* dit,const skiplist_iterator_t* sit){ + (*dit) = (*sit); +} +const void* skiplist_iterator_value(skiplist_iterator_t* it){ + return (*it)->data; +} +void skiplist_iterator_next(skiplist_iterator_t* it){ + (*it) = (*it)->lev[0].next; +} +void skiplist_iterator_prev(skiplist_iterator_t* it){ + (*it) = (*it)->prev; +} +void skiplist_iterator_destroy(skiplist_iterator_t* it){ + ; +}