skiplist *skiplist_new(int max_levels, float level_probability, int allow_duplicates, int append_duplicates, int (*compare_function)(void *,void *)){ skiplist *newlist=NULL; /* alloc memory for new list structure */ if((newlist=(skiplist *)malloc(sizeof(skiplist)))){ /* initialize levels, etc. */ newlist->current_level=0; newlist->max_levels=max_levels; newlist->level_probability=level_probability; newlist->allow_duplicates=allow_duplicates; newlist->append_duplicates=append_duplicates; newlist->items=0; newlist->compare_function=compare_function; /* initialize head node */ newlist->head=skiplist_new_node(newlist,max_levels); } return newlist; }
int skiplist_insert(skiplist *list, void *data){ skiplistnode **update=NULL; skiplistnode *thisnode=NULL; skiplistnode *nextnode=NULL; skiplistnode *newnode=NULL; int level=0; int x=0; if(list==NULL || data==NULL){ return SKIPLIST_ERROR_ARGS; } /* initialize update vector */ if((update=(skiplistnode **)malloc(sizeof(skiplistnode *) * list->max_levels))==NULL){ return SKIPLIST_ERROR_MEMORY; } for(x=0;x<list->max_levels;x++) update[x]=NULL; /* check to make sure we don't have duplicates */ /* NOTE: this could made be more efficient */ if(list->allow_duplicates==FALSE){ if(skiplist_find_first(list,data,NULL)) return SKIPLIST_ERROR_DUPLICATE; } /* find proper position for insert, remember pointers with an update vector */ thisnode=list->head; for(level=list->current_level;level>=0;level--){ while((nextnode=thisnode->forward[level])){ if(list->append_duplicates==TRUE){ if(list->compare_function(nextnode->data,data)>0) break; } else{ if(list->compare_function(nextnode->data,data)>=0) break; } thisnode=nextnode; } update[level]=thisnode; } /* get a random level the new node should be inserted at */ level=skiplist_random_level(list); /*printf("INSERTION LEVEL: %d\n",level);*/ /* we're adding a new level... */ if(level > list->current_level){ /*printf("NEW LEVEL!\n");*/ list->current_level++; level=list->current_level; update[level]=list->head; } /* create a new node */ if((newnode=skiplist_new_node(list,level))==NULL){ /*printf("NODE ERROR\n");*/ free(update); return SKIPLIST_ERROR_MEMORY; } newnode->data=data; /* update pointers to insert node at proper location */ do{ thisnode=update[level]; newnode->forward[level]=thisnode->forward[level]; thisnode->forward[level]=newnode; }while(--level>=0); /* update counters */ list->items++; /* free memory */ free(update); return SKIPLIST_OK; }
static apr_skiplistnode *insert_compare(apr_skiplist *sl, void *data, apr_skiplist_compare comp, int add, apr_skiplist_freefunc myfree) { apr_skiplistnode *m, *p, *tmp, *ret = NULL; int ch, top_nh, nh = 1; ch = skiplist_height(sl); if (sl->preheight) { while (nh < sl->preheight && get_b_rand()) { nh++; } } else { while (nh <= ch && get_b_rand()) { nh++; } } top_nh = nh; /* Now we have in nh the height at which we wish to insert our new node, * and in ch the current height: don't create skip paths to the inserted * element until the walk down through the tree (which decrements ch) * reaches nh. From there, any walk down pushes the current node on a * stack (the node(s) after which we would insert) to pop back through * for insertion later. */ m = sl->top; while (m) { /* * To maintain stability, dups (compared == 0) must be added * AFTER each other. */ if (m->next) { int compared = comp(data, m->next->data); if (compared == 0) { if (!add) { /* Keep the existing element(s) */ skiplist_qclear(&sl->stack_q); return NULL; } if (add < 0) { /* Remove this element and continue with the next node * or the new top if the current one is also removed. */ apr_skiplistnode *top = sl->top; skiplisti_remove(sl, m->next, myfree); if (top != sl->top) { m = sl->top; skiplist_qclear(&sl->stack_q); ch = skiplist_height(sl); nh = top_nh; } continue; } } if (compared >= 0) { m = m->next; continue; } } if (ch <= nh) { /* push on stack */ skiplist_qpush(&sl->stack_q, m); } m = m->down; ch--; } /* Pop the stack and insert nodes */ p = NULL; while ((m = skiplist_qpop(&sl->stack_q))) { tmp = skiplist_new_node(sl); tmp->next = m->next; if (m->next) { m->next->prev = tmp; } m->next = tmp; tmp->prev = m; tmp->up = NULL; tmp->nextindex = tmp->previndex = NULL; tmp->down = p; if (p) { p->up = tmp; } else { /* This sets ret to the bottom-most node we are inserting */ ret = tmp; } tmp->data = data; tmp->sl = sl; p = tmp; } /* Now we are sure the node is inserted, grow our tree to 'nh' tall */ for (; sl->height < nh; sl->height++) { m = skiplist_new_node(sl); tmp = skiplist_new_node(sl); m->up = m->prev = m->nextindex = m->previndex = NULL; m->next = tmp; m->down = sl->top; m->data = NULL; m->sl = sl; if (sl->top) { sl->top->up = m; } else { sl->bottom = sl->bottomend = m; } sl->top = sl->topend = tmp->prev = m; tmp->up = tmp->next = tmp->nextindex = tmp->previndex = NULL; tmp->down = p; tmp->data = data; tmp->sl = sl; if (p) { p->up = tmp; } else { /* This sets ret to the bottom-most node we are inserting */ ret = tmp; } p = tmp; } if (sl->index != NULL) { /* * this is a external insertion, we must insert into each index as * well */ apr_skiplistnode *ni, *li; li = ret; for (p = apr_skiplist_getlist(sl->index); p; apr_skiplist_next(sl->index, &p)) { apr_skiplist *sli = (apr_skiplist *)p->data; ni = insert_compare(sli, ret->data, sli->compare, 1, NULL); li->nextindex = ni; ni->previndex = li; li = ni; } } sl->size++; return ret; }