Next / Previous / Contents / TCC Help System / NM Tech homepage

4.5. The SkipList class

Now we turn to the actual SkipList class. First, the external interface with intended functions:

pyskip.py
# - - - - -   c l a s s   S k i p L i s t   - - - - -

class SkipList:
    """Container class for ordered sets.

      Exports:
        SkipList ( keyFun=None, cmpFun=None, allowDups=0,
                   count=1000000 ):
          [ (keyFun is a function that returns the key for a
             given child object) and
            (cmpFun is a function that compares two keys, using
             the usual Python convention for the cmp() function,
             or None use the built-in cmp() function) and
            (allowDups is 0 to refuse duplicate entries or 1 to
             allow them) and
            (count is a worst-case maximum element count) ->
              return a new, empty SkipList instance with those
              properties ]
        .insert(c):
          [ c is a child object ->
              if ((self contains an object whose key equals the key
                   of e) and (self.allowDups is false)) ->
                raise KeyError
              else ->
                self  :=  self with e added as a new child object ]
        .delete(k):
          [ k is in the key domain ->
              if self contains any child objects with keys equal to k ->
                self  :=  self with the first-inserted such child object
                          deleted
                return that child object
              else ->
                return None ]
        .match(k):
          [ k is in the key domain ->
              if self contains any child objects whose keys equal k ->
                return the first such child object
              else -> raise KeyError ]
        .find(k):
          [ k is in the key domain ->
              if self contains any child objects whose keys are >= k ->
                return an iterator that will iterate over all
                child objects whose keys are >= k, in order ]
        .__len__(self):
          [ return the number of child objects in self ]
        .__iter__(self):
          [ return an iterator that will iterate over all the
            child objects in self in order ]
        .__contains__(self, k):
          [ if self contains any child objects whose keys equal k ->
              return 1
            else -> return 0 ]
        .__delitem__(self, k):      [ same as self.delete(k) ]
        .__getitem__(self, k):      [ same as self.match(k) ]
        .nSearches:  [INVARIANT: Number of searches performed ]
        .nCompares:  [INVARIANT: Number of child pairs compared ]
    """

Next, we declare a manifest constant for the Pugh's p:

pyskip.py
#--
# Manifest constants
#--
    NEW_LEVEL_PROBABILITY   = 0.25  # The `p' of Pugh's article

Next, we need to declare the class's internal state and invariants.

pyskip.py
#================================================================
# State and invariants
#----------------------------------------------------------------
# .keyFun:       [ as passed to constructor, read-only ]
# .cmpFun:       [ as passed to constructor, read-only ]
# .allowDups:    [ as passed to constructor, read-only ]
# .__maxLevels:
#   [ 1 + ceiling ( log (base 4) of count argument to constructor ) ]
# .__nLevels:
#   [ number of levels currently in use ]
#   INVARIANT: 1 <= self.__nLevels <= self.__maxLevels ]
# .__heads:
#   [ list of head pointers to each level ]
#   INVARIANT: self.__heads.links[0] is the head of a linked list
#   of _SkipItem objects, terminated by a link to self.__terminator,
#   and whose members contain all the child objects currently in
#   self, such that for any two adjacent objects (Xi, Xj),
#   children-are-ordered ( Xi, Xj ) is true.
#
#   INVARIANT: For i in [0,self.__maxLevels), the list rooted in
#   heads.links[i] is a linked list of _SkipItem objects,
#   terminated by a link to self.terminator, and containing
#   a subset of the linked list in heads.links[i-1] in the same order.
# .__terminator:    [ terminator for all linked lists ]
#   INVARIANT: self.terminator is a _SkipItem object with
#   self.__maxLevels forward links all pointing to itself
# .__nItems:        [ INVARIANT: number of child items in self ]
#--