CS 261 – SUMMER 2011
Skip Lists
Skip Lists Advantages
Ordinary linked lists and arrays have fast
(O(1)) addition, but slow search
Sorted Vectors have fast search
(O(log n))
but slow insertion
Skip Lists have it all - fast (O(log n)) addition,
search and removal times!
Cost - Slightly more complicated
Start with an ordered list
Lets begin with a simple ordered list,
sentinel on the left, single links.
Start of the struct
definition
struct skiplist {
struct skiplink * sentinel;
int size;
};
Operations
Add (Object newValue) - find correct location,
add the value
Contains (Object testValue) - find correct
location, see if its what we want
Remove (Object testValue) - find correct
location, possibly remove it
See anything in common?
Slide Right
struct skiplink * slideRight (struct skiplink * current,
EleType testValue) {
while ((current->next != 0) && LT(current->next->value,
testValue))
current = current->next;
return current;
}
Finds the link RIGHT BEFORE the place the value we want
should be, if it is there
Add (EleType newValue)
void add (struct skiplist* lst, EleType newValue) {
struct skiplink * current =
slideRight(lst->sentinel, newValue);
struct link * newLink = (struct link *) malloc(sizeof(struct
link));
assert (newLink != 0);
newLink->value = newValue;
newLink->next = current->next;
current->next = newLink;
lst->size++;
}
Contains (EleType testValue)
int contains (struct skip *lst, EleType testValue) {
struct skiplink * current =
slideRight (lst->leftSentinel, testValue);
if ((current->next != 0) &&
(EQ(testValue, current->next->value)))
return true;
return false;
} /* reminder, this is one level list, not real skiplist */
Remove (Object testValue)
void remove (struct skiplist *lst, EleType testValue) {
struct skiplink * current =
slideRight (lst->leftSentinel, testValue);
if ((current->next != 0) &&
(EQ(testValue, current->next->value))) {
current->next = current->next->next;
free(current->next);
lst->size--;
}
}
Problem with Sorted List
What’s the use?
Add is still O(n), so is contains, so is remove.
No better than an ordinary list.
Major problem with list - sequential access
Why no binary search?
What if we kept a link to middle of list?
But need to keep going
And going and going
In theory it would work…..
In theory this would work
Would give us nice O(log n) search
But would be really hard to maintain as
values were inserted and removed
What about if we relax the rules, and don’t try
to be so precise…..
The power of probability
Instead of being precise, keep a hierarchy of
ordered lists with downward pointers
Each list has approximately half the elements
of the one below
So, if the bottom list has n elements, how
many levels are there??
Picture of Skip List
Slightly bigger list
Contains (Object testValue)
Starting at topmost sentinel, slide right
If next value is it, return true
If next value is not what we are looking for,
move down and slide right
If we get to bottom without finding it, return
false
Notes about contains
See how it makes a zig-zag from top to
bottom
On average, slide only moves one or two
positions
So basically proportional to height of
structure
Which is????? O( ?? )
Remove Algorithm
Start at topmost sentinal
Loop as follows
Slide right. If next element is the one we want,
remove it
If no down element, reduce size
Move down
Notice about Remove
Only want to decrement size counter if at
bottom level
Again, makes zig-zag motion to bottom, is
proportional to height
So it is again O(log n)
Add (Object newElement)
Now we come to addition - the most complex
operation.
Intuitive idea - add to bottom row (remember to
increment count)
Move upwards, flipping a coin
As long as heads, add to next higher row
At top, again flip, if heads make new row
Add Example
Insert the following: 9 14 7 3 20
Coin toss: T H T H H T T H T (insert if heads)
The Power of Chance
At each step we flip a coin
So the exact structure is not predictable, and
will be different even if you add the same
elements in same order over again
But the gross structure is predictable,
because if you flip a coin N times as N gets
large you expect N/2 to be heads.
Notes on Add
Again proportional to height of structure, not
number of nodes in list
So also O(log n)
So all three operations are O(log n) !
By far the fastest overall Bag structure we
have seen!
(Downside - does use a lot of memory as values are repeated. But who cares
about memory? )
int skipListContains(struct skipList* slst, EleType d) {
struct skipLink *tmp = slst->topSentinel;
while (tmp != 0) {
tmp = slideRight(tmp, d);
if ((tmp->next != 0) && EQ(d, tmp->next>value))
return 1;
tmp = tmp->down;
}
return 0;
}
void skipListAdd(struct skipList * slst, EleType d) {
struct skipLink *downLink, *newLink;
downLink = skipLinkAdd(slideRight(slst>topSentinel,d),d);
if (downLink != 0 && skipFlip()) {
newLink = newSkipLink(d, 0, downLink);
slst->topSentinel = newSkipLink(0, newLink,
slst->topSentinel);
}
slst->size++;
}
struct skipLink* skipLinkAdd(struct skipLink * current, EleType d) {
struct skipLink *newLink, *downLink;
newLink = 0;
if (current->down == 0) {
newLink = newSkipLink(d, current->next, 0);
current->next = newLink;
}
else {
downLink = skipLinkAdd(slideRight(current->down, d), d);
if (downLink != 0 && skipFlip()) {
newLink = newSkipLink(d, current->next, downLink);
current->next = newLink;
}
}
return newLink;
}
struct skipLink* newSkipLink(EleType d, struct skipLink
* nlnk, struct skipLink* dlnk) {
struct skipLink * tmp = (struct skipLink *)
malloc(sizeof(struct skipLink));
assert(tmp != 0);
tmp->value = d;
tmp->next = nlnk;
tmp->down = dlnk;
return tmp;
}
int skipFlip() { return rand() % 2; }
void skipListRemove(struct skipList* slst, EleType d) {
struct skipLink *current, *tmp;
current = slst->topSentinel;
while (current != 0) {
current = slideRight(current, d);
if (current->next != 0 && EQ(d, current->next->value)) {
tmp = current->next;
current->next = current->next->next;
free(tmp);
if (current->down != 0)
slst->size--;
}
current = current->down;
}
}
© Copyright 2026 Paperzz