int skiplist_insert(skiplist *list, int key, int value) { snode *update[SKIPLIST_MAX_LEVEL+1]; snode *x = list->header; int i, level; for (i = list->level; i >= 1; i--) { while (x->forward[i]->key < key) x = x->forward[i]; update[i] = x; } x = x->forward[1]; if (key == x->key) { x->value = value; return 0; } else { level = rand_level(); if (level > list->level) { for (i = list->level+1; i <= level; i++) { update[i] = list->header; } list->level = level; } x = (snode *)malloc(sizeof(snode)); x->key = key; x->value = value; x->forward = (snode **)malloc(sizeof(snode*) * (level + 1)); for (i = 1; i <= level; i++) { x->forward[i] = update[i]->forward[i]; update[i]->forward[i] = x; } } return 0; }
int skiplist_insert_raw(SkipList *list, unsigned char *key, void *value, int(* cmp)(unsigned char *, unsigned char *)) { Node *update[SKIPLIST_MAX_LEVEL + 1]; Node *x = list->header; int i, level; for(i = list->level; i >= 1; i--) { while(cmp(x->forward[i]->key, key) < 0) { x = x->forward[i]; } update[i] = x; } x = x->forward[1]; if (cmp(key, x->key) == 0) { return 1; } /* if (key == x->key) { free(x->value); x->value = value; return 0; } */ else { level = rand_level(); if (level > list->level) { for(i = list->level + 1; i <= level; i++) { update[i] = list->header; } list->level = level; } x = (Node *)malloc(sizeof(Node)); if (x == NULL) { printf("Error skiplist_insert_raw, allocate Node failed.\n"); return -1; } x->key = key; x->value = value; x->forward = (Node **)malloc(sizeof(Node *) * (level + 1)); for(i = 1; i <= level; i++) { x->forward[i] = update[i]->forward[i]; update[i]->forward[i] = x; } } return 0; }
/** * 跳表的插入操作要点 * 1 找到带插入的位置(在当前元素的前向指针的键与元素的键相等或者大于的适合退出),然后再更新在每个层次的update数组 * 2 随机生成新节点的level * 3 调整指向,插入新节点 */ void *skiplist_insert(skiplist_t *l,void *item){ skiplist_node_t *cur=l->head; skiplist_node_t **update=l->update; int (*comp)(const void *,const void *); comp=l->comp; int i; /*查找键所属的位置*/ for(i=l->level;i>=0;i--){ while(cur->forward[i]!=NULL &&comp(cur->forward[i]->item,item)<0) cur=cur->forward[i]; //在当前层次遍历直至前向指针为NULL或者对应的前向指针的元素大于或等于item update[i]=cur; //更新插入位置的前驱指针 } cur=cur->forward[0]; if(cur!=NULL&&comp(cur->item,item)==0) return cur->item; //键值已存在,直接返回原来的节点 int level=rand_level(l->prob,l->max_level); //最大的level控制在max_level if(level> l->level){ //如果新生成的层数比跳表层数大,更新下标大于i的update数组指向为头结点 for(i=l->level+1;i<=level;i++){ //持续到当前生成的level上 update[i]=l->head; } l->level=level; //更新自己的层级数 } skiplist_node_t *tmp=new_skiplist_node(level,item); /** * 调整前向指针的指向,插入新结点 * 问题就出现在这里,注意如果生成的level级别较低,只需要在从0..level的级别进行插入,切记不能使用l->level * l->level和level是有不同的,除非level大于当前跳表的level时 */ for(i=0;i<=level;i++){ tmp->forward[i]=update[i]->forward[i]; update[i]->forward[i]=tmp; } l->n++; return NULL; }