A Skip List Cookbook
4
Search(list, searchKey)
x := list→header
-- loop invariant: x→key < searchKey
for i := list→level downto 1 do
while x→forward[i]→key < searchKey do
x := x→forward[i]
-- x→key < searchKey
≤
x→forward[1]→key
x := x→forward[1]
if x→key = searchKey then return x→value
else return failure
FIGURE 2 - Skip list search algorithm
Insert(list, searchKey, newValue)
local update[1..MaxLevel]
x := list→header
for i := list→level downto 1 do
while x→forward[i]→key < searchKey do
x := x→forward[i]
update[i] := x
x := x→forward[1]
if x→key = searchKey then x→value := newValue
else
newLevel := randomLevel()
if newLevel > list→level then
for i := list→level + 1 to newLevel do
update[i] := list→header
list→level := newLevel
x := makeNode(newLevel , searchKey, value)
for i := 1 to newLevel do
x→forward[i] := update[i]→forward[i]
update[i]→forward[i] := x
Delete(list, searchKey)
local update[1..MaxLevel]
x := list→header
for i := list→level downto 1 do
while x→forward[i]→key < searchKey do
x := x→forward[i]
update[i] := x
x := x→forward[1]
if x→key = searchKey then
for i := 1 to list→level do
if update[i]→forward[i] ≠ x then break
update[i]→forward[i] := x→forward[i]
free(x)
while list→level > 1 and
list→header→forward[list→level] = NIL do
list→level := list→level – 1
FIGURE 3 - Insertion and deletion algorithms
The Delete operation deletes the specified key.
Each element is represented by a node, the level of
which is chosen randomly when the node is inserted
without regard for the number of elements in the data
structure. A level i node has i forward pointers, indexed
1 through i. We do not need to store the level of a node
in the node. Levels are capped at some appropriate con-
stant MaxLevel. The level of a list is the maximum level
currently in the list (or 1 if the list is empty). The
header of a list has forward pointers at levels one
through MaxLevel. The forward pointers of the header
at levels higher than the current maximum level of the
list point to NIL.
Initialization
An element NIL is given a key greater than any legal
key. All levels of all skip lists are terminated with NIL.
A new list is initialized so that the level of the list is
equal to 1 and all forward pointers of the list’s header
point to NIL.
Search Algorithm
We search for an element by traversing forward
pointers that do not overshoot the node containing the
element being searched for (Figure 2). When no more
progress can be made at the current level of forward
pointers, the search moves down to the next level.
When we can make no more progress at level 1, we
must be immediately in front of the node that contains
the desired element (if it is in the list).
Insertion and Deletion Algorithms
To insert or delete a node, we simply search and splice.
Figure 3 gives algorithms for insertion and deletion. A
vector update is maintained so that when the search is
complete (and we are ready to perform the splice),
update[i] contains a pointer to the rightmost node of
level i or higher that is to the left of the location of the
insertion/deletion. If an insertion generates a node with
a level greater than the previous maximum level of the
list, we update the maximum level of the list and
initialize the appropriate portions of the update vector.
After each deletion, we check if we have deleted the
maximum element of the list and if so, decrease the
maximum level of the list.
Generating a Random Level
Initially, we discussed a probability distribution where half of the nodes that have level i pointers also have level i+1
pointers. To get away from magic constants, we say that a fraction p of the nodes with level i pointers also have
level i+1 pointers. (for our original discussion, p = 1/2). Levels are generated randomly by an algorithm equivalent
to the one in Figure 4. Levels are generated without reference to the number of elements in the list.