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

4.17. SkipList.delete()

Deletion, like insertion, also uses the idea of a cut list, that is, a list of all the predecessors whose links must be repaired to leave out the deleted item.

However, deletion uses a slightly different concept of the cut list, the search cut list. The only difference comes when the skip list allows duplicate keys. When we're inserting a child with a duplicate key, we want it to go after the other children with that key, to guarantee stability.

For deletion and searching, however, we want the cut list to point before the first of any values whose keys are equal to the key we're deleting or searching for.
# - - -   S k i p L i s t . d e l e t e   - - -

    def delete ( self, key ):
        """Delete the first or only child with a given key value.

First we find the search cut list for the given key. We also set local variables prevItem and nextItem to point to the predecessor and successor of the cut point at level 0. See Section 4.18, “SkipList.__searchCutList().
        #-- 1 --
        # [ cutList   :=  search-cut-list ( key )
        #   prevItem  :=  first element of search-cut-list ( key )
        #   nextItem  :=  successor to first element of
        #                 search-cut-list ( key ) ]
        cutList   =  self.__searchCutList ( key )
        prevItem  =  cutList[0]
        nextItem  =  prevItem.links[0]

If the cut point is before the terminator, or the element after the cut point does not have the key value we're looking for, we're done, and we return None to signify failure to delete anything. See Section 4.13, “SkipList.__compareItemKey().
        #-- 2 --
        # [ if (nextItem is self.__terminator) or
        #   ( cmp ( key-of ( nextItem's child ), key ) ) > 0 ) ->
        #     return None
        #   else -> I ]
        if ( ( nextItem is self.__terminator ) or
             ( self.__compareItemKey ( nextItem, key ) > 0 ) ):
            return None

We've found the item to be deleted, and nextItem points to it. Relink all the lists that point at that item so that the predecessor at that level in the cut list points at nextItem's successor at that level.
        #-- 3 --
        # [ self  :=  self modified so that for all I in
        #             [0,self.__nLevels), if the skipItem pointed to by
        #             cutList[I] has an (I)th link that points to
        #             nextItem, make that link point where nextItem's
        #             (I)th link points ]
        for i in xrange(self.__nLevels):
            #-- 3 body --
            # [ if the _SkipItem pointed to by cutList[i] has an
            #   (i)th link that points to nextItem ->
            #     that link is made to point where nextItem's (i)th
            #     link points ]
            prevItem  =  cutList[i]
            if  prevItem.links[i] is nextItem:
                prevItem.links[i]  =  nextItem.links[i]

Finally, we must adjust .__nItems to reflect the deletion of one child, and return the deleted child value.

We must also set the level-0 link in the deleted _SkipItem to None, for reasons discussed in Section 3.4, “Classes in this module”.
        #-- 4 --
        self.__nItems      =  self.__nItems - 1
        nextItem.links[0]  =  None
        return nextItem.child