rbtree.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # This code adapted from C source from
00004 # Thomas Niemann's Sorting and Searching Algorithms: A Cookbook
00005 #
00006 # From the title page:
00007 #   Permission to reproduce this document, in whole or in part, is
00008 #   given provided the original web site listed below is referenced,
00009 #   and no additional restrictions apply. Source code, when part of
00010 #   a software project, may be used freely without reference to the
00011 #   author.
00012 #
00013 # Adapted by Chris Gonnerman <chris.gonnerman@newcenturycomputers.net>
00014 #        and Graham Breed
00015 #
00016 # Updated by Charles Tolman <ct@acm.org>
00017 #        inheritance from object class
00018 #        added RBTreeIter class
00019 #        added lastNode and prevNode routines to RBTree
00020 #        added RBList class and associated tests
00021 #
00022 # Updated by Stefan Fruhner <marycue@gmx.de>
00023 #        Added item count to RBNode, which counts the occurence
00024 #        of objects. The tree is kept unique, but insertions 
00025 #        of the same object are counted
00026 #        changed RBList.count():  returns the number of occurences of 
00027 #                                 an item
00028 #        Renamed RBList.count to RBList.elements, because of a name 
00029 #        mismatch with RBList.count()
00030 #        changed RBTree.insertNode to count insertions of the same item
00031 #        changed RBList.insert(): uncommented some superfluid code
00032 #        changed RBList.remove(): If called with all=True, then all instances
00033 #                                 of the node are deleted from the tree;
00034 #                                 else only node.count is decremented,
00035 #                                 if finally node.count is 1 the node 
00036 #                                 is deleted.  all is True by default.
00037 #        changed RBTree.deleteNode : same changes as for RBList.remove()
00038 #        finally I've changed the __version__ string to '1.6'
00039 
00040 __version__ = "1.6"
00041 
00042 import string
00043 
00044 BLACK = 0
00045 RED = 1
00046 
00047 class RBNode(object):
00048 
00049     def __init__(self, key = None, value = None, color = RED):
00050         self.left = self.right = self.parent = None
00051         self.color = color
00052         self.key = key
00053         self.value = value
00054         self.nonzero = 1
00055         self.count = 1
00056 
00057     def __str__(self):
00058         return repr(self.key) + ': ' + repr(self.value)
00059 
00060     def __nonzero__(self):
00061         return self.nonzero
00062 
00063     ##
00064     # imitate sequence
00065     def __len__(self):
00066         return 2
00067 
00068     ##
00069     # imitate sequence
00070     def __getitem__(self, index):
00071         if index==0:
00072             return self.key
00073         if index==1:
00074             return self.value
00075         raise IndexError('only key and value as sequence')
00076 
00077 
00078 class RBTreeIter(object):
00079 
00080     def __init__ (self, tree):
00081         self.tree = tree
00082         self.index = -1  # ready to iterate on the next() call
00083         self.node = None
00084         self.stopped = False
00085 
00086     ##
00087     #  Return the current item in the container
00088     #         
00089     def __iter__ (self):
00090         return self.node.value
00091 
00092     ##
00093     #  Return the next item in the container
00094     #             Once we go off the list we stay off even if the list changes
00095     #         
00096     def next (self):
00097         if self.stopped or (self.index + 1 >= self.tree.__len__()):
00098             self.stopped = True
00099             raise StopIteration
00100         #
00101         self.index += 1
00102         if self.index == 0:
00103             self.node = self.tree.firstNode()
00104         else:
00105             self.node = self.tree.nextNode (self.node)
00106         return self.node.value
00107 
00108 
00109 class RBTree(object):
00110 
00111     def __init__(self, cmpfn=cmp, unique=True):
00112         self.sentinel = RBNode()
00113         self.sentinel.left = self.sentinel.right = self.sentinel
00114         self.sentinel.color = BLACK
00115         self.sentinel.nonzero = 0
00116         self.root = self.sentinel
00117         self.elements = 0
00118         
00119         #SF: If self.unique is True, all elements in the tree have 
00120         #SF  to be unique and an exception is raised for multiple 
00121         #SF insertions of a node
00122         #SF If self.unique is set to False, nodes can be added multiple 
00123         #SF times. There is still only one node, but all insertions are
00124         #SF counted in the variable node.count
00125         self.unique = unique
00126         # changing the comparison function for an existing tree is dangerous!
00127         self.__cmp = cmpfn
00128 
00129     def __len__(self):
00130         return self.elements
00131 
00132     def __del__(self):
00133         # unlink the whole tree
00134 
00135         s = [ self.root ]
00136 
00137         if self.root is not self.sentinel:
00138             while s:
00139                 cur = s[0]
00140                 if cur.left and cur.left != self.sentinel:
00141                     s.append(cur.left)
00142                 if cur.right and cur.right != self.sentinel:
00143                     s.append(cur.right)
00144                 cur.right = cur.left = cur.parent = None
00145                 cur.key = cur.value = None
00146                 s = s[1:]
00147 
00148         self.root = None
00149         self.sentinel = None
00150 
00151     def __str__(self):
00152         return "<RBTree object>"
00153 
00154     def __repr__(self):
00155         return "<RBTree object>"
00156 
00157     def __iter__ (self):
00158         return RBTreeIter (self)
00159 
00160     def rotateLeft(self, x):
00161 
00162         y = x.right
00163 
00164         # establish x.right link
00165         x.right = y.left
00166         if y.left != self.sentinel:
00167             y.left.parent = x
00168 
00169         # establish y.parent link
00170         if y != self.sentinel:
00171             y.parent = x.parent
00172         if x.parent:
00173             if x == x.parent.left:
00174                 x.parent.left = y
00175             else:
00176                 x.parent.right = y
00177         else:
00178             self.root = y
00179 
00180         # link x and y
00181         y.left = x
00182         if x != self.sentinel:
00183             x.parent = y
00184 
00185     def rotateRight(self, x):
00186 
00187         #***************************
00188         #  rotate node x to right
00189         #***************************
00190 
00191         y = x.left
00192 
00193         # establish x.left link
00194         x.left = y.right
00195         if y.right != self.sentinel:
00196             y.right.parent = x
00197 
00198         # establish y.parent link
00199         if y != self.sentinel:
00200             y.parent = x.parent
00201         if x.parent:
00202             if x == x.parent.right:
00203                 x.parent.right = y
00204             else:
00205                 x.parent.left = y
00206         else:
00207             self.root = y
00208 
00209         # link x and y
00210         y.right = x
00211         if x != self.sentinel:
00212             x.parent = y
00213 
00214     def insertFixup(self, x):
00215         #************************************
00216         #  maintain Red-Black tree balance  *
00217         #  after inserting node x           *
00218         #************************************
00219 
00220         # check Red-Black properties
00221 
00222         while x != self.root and x.parent.color == RED:
00223 
00224             # we have a violation
00225 
00226             if x.parent == x.parent.parent.left:
00227 
00228                 y = x.parent.parent.right
00229 
00230                 if y.color == RED:
00231                     # uncle is RED
00232                     x.parent.color = BLACK
00233                     y.color = BLACK
00234                     x.parent.parent.color = RED
00235                     x = x.parent.parent
00236 
00237                 else:
00238                     # uncle is BLACK
00239                     if x == x.parent.right:
00240                         # make x a left child
00241                         x = x.parent
00242                         self.rotateLeft(x)
00243 
00244                     # recolor and rotate
00245                     x.parent.color = BLACK
00246                     x.parent.parent.color = RED
00247                     self.rotateRight(x.parent.parent)
00248             else:
00249 
00250                 # mirror image of above code
00251 
00252                 y = x.parent.parent.left
00253 
00254                 if y.color == RED:
00255                     # uncle is RED
00256                     x.parent.color = BLACK
00257                     y.color = BLACK
00258                     x.parent.parent.color = RED
00259                     x = x.parent.parent
00260 
00261                 else:
00262                     # uncle is BLACK
00263                     if x == x.parent.left:
00264                         x = x.parent
00265                         self.rotateRight(x)
00266 
00267                     x.parent.color = BLACK
00268                     x.parent.parent.color = RED
00269                     self.rotateLeft(x.parent.parent)
00270 
00271         self.root.color = BLACK
00272 
00273     def insertNode(self, key, value):
00274         #**********************************************
00275         #  allocate node for data and insert in tree  *
00276         #**********************************************
00277 
00278         # we aren't interested in the value, we just
00279         # want the TypeError raised if appropriate
00280         hash(key)
00281 
00282         # find where node belongs
00283         current = self.root
00284         parent = None
00285         while current != self.sentinel:
00286             # GJB added comparison function feature
00287             # slightly improved by JCG: don't assume that ==
00288             # is the same as self.__cmp(..) == 0
00289             rc = self.__cmp(key, current.key)
00290             if rc == 0:
00291                 #SF This item is inserted for the second, 
00292                 #SF third, ... time, so we have to increment 
00293                 #SF the count
00294                 if self.unique == False: 
00295                     current.count += 1
00296                 else: # raise an Error
00297                     print "Warning: This element is already in the list ... ignored!"
00298                     #SF I don't want to raise an error because I want to keep 
00299                     #SF the code compatible to previous versions
00300                     #SF But here would be the right place to do this
00301                     #raise IndexError ("This item is already in the tree.")
00302                 return current
00303             parent = current
00304             if rc < 0:
00305                 current = current.left
00306             else:
00307                 current = current.right
00308 
00309         # setup new node
00310         x = RBNode(key, value)
00311         x.left = x.right = self.sentinel
00312         x.parent = parent
00313 
00314         self.elements = self.elements + 1
00315 
00316         # insert node in tree
00317         if parent:
00318             if self.__cmp(key, parent.key) < 0:
00319                 parent.left = x
00320             else:
00321                 parent.right = x
00322         else:
00323             self.root = x
00324 
00325         self.insertFixup(x)
00326         return x
00327 
00328     def deleteFixup(self, x):
00329         #************************************
00330         #  maintain Red-Black tree balance  *
00331         #  after deleting node x            *
00332         #************************************
00333 
00334         while x != self.root and x.color == BLACK:
00335             if x == x.parent.left:
00336                 w = x.parent.right
00337                 if w.color == RED:
00338                     w.color = BLACK
00339                     x.parent.color = RED
00340                     self.rotateLeft(x.parent)
00341                     w = x.parent.right
00342 
00343                 if w.left.color == BLACK and w.right.color == BLACK:
00344                     w.color = RED
00345                     x = x.parent
00346                 else:
00347                     if w.right.color == BLACK:
00348                         w.left.color = BLACK
00349                         w.color = RED
00350                         self.rotateRight(w)
00351                         w = x.parent.right
00352 
00353                     w.color = x.parent.color
00354                     x.parent.color = BLACK
00355                     w.right.color = BLACK
00356                     self.rotateLeft(x.parent)
00357                     x = self.root
00358 
00359             else:
00360                 w = x.parent.left
00361                 if w.color == RED:
00362                     w.color = BLACK
00363                     x.parent.color = RED
00364                     self.rotateRight(x.parent)
00365                     w = x.parent.left
00366 
00367                 if w.right.color == BLACK and w.left.color == BLACK:
00368                     w.color = RED
00369                     x = x.parent
00370                 else:
00371                     if w.left.color == BLACK:
00372                         w.right.color = BLACK
00373                         w.color = RED
00374                         self.rotateLeft(w)
00375                         w = x.parent.left
00376 
00377                     w.color = x.parent.color
00378                     x.parent.color = BLACK
00379                     w.left.color = BLACK
00380                     self.rotateRight(x.parent)
00381                     x = self.root
00382 
00383         x.color = BLACK
00384 
00385     def deleteNode(self, z, all=True):
00386         #****************************
00387         #  delete node z from tree  *
00388         #****************************
00389 
00390         if not z or z == self.sentinel:
00391             return
00392             
00393         #SF If the object is in this tree more than once the node 
00394         #SF has not to be deleted. We just have to decrement the 
00395         #SF count variable
00396         #SF we don't have to check for uniquness because this was
00397         #SF already captured in insertNode() and for this reason 
00398         #SF z.count cannot be greater than 1
00399         #SF If all=True then the complete node has to be deleted
00400         if z.count > 1 and not all: 
00401             z.count -= 1
00402             return          
00403 
00404         if z.left == self.sentinel or z.right == self.sentinel:
00405             # y has a self.sentinel node as a child
00406             y = z
00407         else:
00408             # find tree successor with a self.sentinel node as a child
00409             y = z.right
00410             while y.left != self.sentinel:
00411                 y = y.left
00412 
00413         # x is y's only child
00414         if y.left != self.sentinel:
00415             x = y.left
00416         else:
00417             x = y.right
00418 
00419         # remove y from the parent chain
00420         x.parent = y.parent
00421         if y.parent:
00422             if y == y.parent.left:
00423                 y.parent.left = x
00424             else:
00425                 y.parent.right = x
00426         else:
00427             self.root = x
00428 
00429         if y != z:
00430             z.key = y.key
00431             z.value = y.value
00432 
00433         if y.color == BLACK:
00434             self.deleteFixup(x)
00435 
00436         del y
00437         self.elements = self.elements - 1
00438 
00439     def findNode(self, key):
00440         #******************************
00441         #  find node containing data
00442         #******************************
00443 
00444         # we aren't interested in the value, we just
00445         # want the TypeError raised if appropriate
00446         hash(key)
00447         
00448         current = self.root
00449 
00450         while current != self.sentinel:
00451             # GJB added comparison function feature
00452             # slightly improved by JCG: don't assume that ==
00453             # is the same as self.__cmp(..) == 0
00454             rc = self.__cmp(key, current.key)
00455             if rc == 0:
00456                 return current
00457             else:
00458                 if rc < 0:
00459                     current = current.left
00460                 else:
00461                     current = current.right
00462 
00463         return None
00464 
00465     def traverseTree(self, f):
00466         if self.root == self.sentinel:
00467             return
00468         s = [ None ]
00469         cur = self.root
00470         while s:
00471             if cur.left:
00472                 s.append(cur)
00473                 cur = cur.left
00474             else:
00475                 f(cur)
00476                 while not cur.right:
00477                     cur = s.pop()
00478                     if cur is None:
00479                         return
00480                     f(cur)
00481                 cur = cur.right
00482         # should not get here.
00483         return
00484 
00485     ##
00486     # return all nodes as a list
00487     def nodesByTraversal(self):
00488         result = []
00489         def traversalFn(x, K=result):
00490             K.append(x)
00491         self.traverseTree(traversalFn)
00492         return result
00493 
00494     ##
00495     # return all nodes as a list
00496     def nodes(self):
00497         cur = self.firstNode()
00498         result = []
00499         while cur:
00500             result.append(cur)
00501             cur = self.nextNode(cur)
00502         return result
00503 
00504     def firstNode(self):
00505         cur = self.root
00506         while cur.left:
00507             cur = cur.left
00508         return cur
00509 
00510     def lastNode(self):
00511         cur = self.root
00512         while cur.right:
00513             cur = cur.right
00514         return cur
00515 
00516     ##
00517     # returns None if there isn't one
00518     def nextNode(self, prev):
00519         cur = prev
00520         if cur.right:
00521             cur = prev.right
00522             while cur.left:
00523                 cur = cur.left
00524             return cur
00525         while 1:
00526             cur = cur.parent
00527             if not cur:
00528                 return None
00529             if self.__cmp(cur.key, prev.key)>=0:
00530                 return cur
00531 
00532     ##
00533     # returns None if there isn't one
00534     def prevNode(self, next):
00535         cur = next
00536         if cur.left:
00537             cur = next.left
00538             while cur.right:
00539                 cur = cur.right
00540             return cur
00541         while 1:
00542             cur = cur.parent
00543             if cur is None:
00544                 return None
00545             if self.__cmp(cur.key, next.key)<0:
00546                 return cur
00547 
00548 
00549 ##
00550 #  List class uses same object for key and value
00551 #         Assumes you are putting sortable items into the list.
00552 #     
00553 class RBList(RBTree):
00554 
00555     def __init__(self, list=[], cmpfn=cmp, unique=True):
00556         #SF new option: unique trees, see RBTree.__init__() for 
00557         #SF more information
00558         RBTree.__init__(self, cmpfn, unique)
00559         for item in list:
00560             self.insertNode (item, item)
00561 
00562     def __getitem__ (self, index):
00563         node = self.findNodeByIndex (index)
00564         return node.value
00565 
00566     def __delitem__ (self, index):
00567         node = self.findNodeByIndex (index)
00568         self.deleteNode (node)
00569 
00570     def __contains__ (self, item):
00571         return self.findNode (item) is not None
00572 
00573     def __str__ (self):
00574         # eval(str(self)) returns a regular list
00575         return '['+ string.join(map(lambda x: str(x.value), self.nodes()), ', ')+']'
00576 
00577     def findNodeByIndex (self, index):
00578         if (index < 0) or (index >= self.elements):
00579             raise IndexError ("pop index out of range")
00580         #
00581         if index < self.elements / 2:
00582             # simple scan from start of list
00583             node = self.firstNode()
00584             currIndex = 0
00585             while currIndex < index:
00586                 node = self.nextNode (node)
00587                 currIndex += 1
00588         else:
00589             # simple scan from end of list
00590             node = self.lastNode()
00591             currIndex = self.elements - 1
00592             while currIndex > index:
00593                 node = self.prevNode (node)
00594                 currIndex -= 1
00595         #
00596         return node
00597 
00598     def insert (self, item):
00599         #SF The function inserNode already checks for existing Nodes 
00600         #SF so this code seems to be superfluid
00601         #node = self.findNode (item)
00602         #if node is not None:
00603             #self.deleteNode (node)
00604         # item is both key and value for a list
00605         self.insertNode (item, item)
00606 
00607     def append (self, item):
00608         # list is always sorted
00609         self.insert (item)
00610 
00611     #SF this function is not implemented as a common list in python
00612     #def count (self):
00613         #return len(self)
00614         
00615     #SF Because we count all equal items in one node 
00616     #SF we now can use the function count as used in 
00617     #SF common python lists
00618     def count(self, item):
00619         node = self.findNode (item)
00620         return node.count
00621 
00622     def index (self, item):
00623         index = -1
00624         node = self.findNode (item)
00625         while node is not None:
00626             node = self.prevNode (node)
00627             index += 1
00628         #
00629         if index < 0:
00630             raise ValueError ("RBList.index: item not in list")
00631         return index
00632 
00633     def extend (self, otherList):
00634         for item in otherList:
00635             self.insert (item)
00636 
00637     def pop (self, index=None):
00638         if index is None:
00639             index = self.elements - 1
00640         #
00641         node = self.findNodeByIndex (index)
00642         value = node.value      # must do this before removing node
00643         self.deleteNode (node)
00644         return value
00645 
00646     def remove (self, item, all=True):
00647         #SF When called with all=True then all occurences are deleted
00648         node = self.findNode (item)
00649         if node is not None:
00650             self.deleteNode (node, all)
00651 
00652     def reverse (self): # not implemented
00653         raise AssertionError ("RBlist.reverse Not implemented")
00654 
00655     def sort (self): # Null operation
00656         pass
00657 
00658     ##
00659     # delete all entries
00660     def clear (self):
00661         self.__del__()
00662         #copied from RBTree constructor
00663         self.sentinel = RBNode()
00664         self.sentinel.left = self.sentinel.right = self.sentinel
00665         self.sentinel.color = BLACK
00666         self.sentinel.nonzero = 0
00667         self.root = self.sentinel
00668         self.elements = 0
00669 
00670     def values (self):
00671         return map (lambda x: x.value, self.nodes())
00672 
00673     def reverseValues (self):
00674         values = map (lambda x: x.value, self.nodes())
00675         values.reverse()
00676         return values
00677 
00678 
00679 class RBDict(RBTree):
00680 
00681     def __init__(self, dict={}, cmpfn=cmp):
00682         RBTree.__init__(self, cmpfn)
00683         for key, value in dict.items():
00684             self[key]=value
00685 
00686     def __str__(self):
00687         # eval(str(self)) returns a regular dictionary
00688         return '{'+ string.join(map(str, self.nodes()), ', ')+'}'
00689 
00690     def __repr__(self):
00691         return "<RBDict object " + str(self) + ">"
00692 
00693     def __getitem__(self, key):
00694         n = self.findNode(key)
00695         if n:
00696             return n.value
00697         raise IndexError
00698 
00699     def __setitem__(self, key, value):
00700         n = self.findNode(key)
00701         if n:
00702             n.value = value
00703         else:
00704             self.insertNode(key, value)
00705 
00706     def __delitem__(self, key):
00707         n = self.findNode(key)
00708         if n:
00709             self.deleteNode(n)
00710         else:
00711             raise IndexError
00712 
00713     def get(self, key, default=None):
00714         n = self.findNode(key)
00715         if n:
00716             return n.value
00717         return default
00718 
00719     def keys(self):
00720         return map(lambda x: x.key, self.nodes())
00721 
00722     def values(self):
00723         return map(lambda x: x.value, self.nodes())
00724 
00725     def items(self):
00726         return map(tuple, self.nodes())
00727 
00728     def has_key(self, key):
00729         return self.findNode(key) <> None
00730 
00731     ##
00732     # delete all entries
00733     def clear(self):
00734 
00735         self.__del__()
00736 
00737         #copied from RBTree constructor
00738         self.sentinel = RBNode()
00739         self.sentinel.left = self.sentinel.right = self.sentinel
00740         self.sentinel.color = BLACK
00741         self.sentinel.nonzero = 0
00742         self.root = self.sentinel
00743         self.elements = 0
00744 
00745     ##
00746     # return shallow copy
00747     def copy(self):
00748         # there may be a more efficient way of doing this
00749         return RBDict(self)
00750 
00751     ##
00752     # Add all items from the supplied mapping to this one.
00753     # 
00754     #         Will overwrite old entries with new ones.
00755     # 
00756     #         
00757     def update(self, other):
00758         for key in other.keys():
00759             self[key] = other[key]
00760 
00761     def setdefault(self, key, value=None):
00762         if self.has_key(key):
00763             return self[key]
00764         self[key] = value
00765         return value
00766 
00767 
00768 """ ----------------------------------------------------------------------------
00769     TEST ROUTINES
00770 """
00771 def testRBlist():
00772     import random
00773     print "--- Testing RBList ---"
00774     print "    Basic tests..."
00775 
00776     initList = [5,3,6,7,2,4,21,8,99,32,23]
00777     rbList = RBList (initList)
00778     initList.sort()
00779     assert rbList.values() == initList
00780     initList.reverse()
00781     assert rbList.reverseValues() == initList
00782     #
00783     rbList = RBList ([0,1,2,3,4,5,6,7,8,9])
00784     for i in range(10):
00785         assert i == rbList.index (i)
00786 
00787     # remove odd values
00788     for i in range (1,10,2):
00789         rbList.remove (i)
00790     assert rbList.values() == [0,2,4,6,8]
00791 
00792     # pop tests
00793     assert rbList.pop() == 8
00794     assert rbList.values() == [0,2,4,6]
00795     assert rbList.pop (1) == 2
00796     assert rbList.values() == [0,4,6]
00797     assert rbList.pop (0) == 0
00798     assert rbList.values() == [4,6]
00799 
00800     # Random number insertion test
00801     rbList = RBList()
00802     for i in range(5):
00803         k = random.randrange(10) + 1
00804         rbList.insert (k)
00805     print "    Random contents:", rbList
00806 
00807     rbList.insert (0)
00808     rbList.insert (1)
00809     rbList.insert (10)
00810 
00811     print "    With 0, 1 and 10:", rbList
00812     n = rbList.findNode (0)
00813     print "    Forwards:",
00814     while n is not None:
00815         print "(" + str(n) + ")",
00816         n = rbList.nextNode (n)
00817     print
00818 
00819     n = rbList.findNode (10)
00820     print "    Backwards:",
00821     while n is not None:
00822         print "(" + str(n) + ")",
00823         n = rbList.prevNode (n)
00824 
00825     if rbList.nodes() != rbList.nodesByTraversal():
00826         print "node lists don't match"
00827     print
00828 
00829 def testRBdict():
00830     import random
00831     print "--- Testing RBDict ---"
00832 
00833     rbDict = RBDict()
00834     for i in range(10):
00835         k = random.randrange(10) + 1
00836         rbDict[k] = i
00837     rbDict[1] = 0
00838     rbDict[2] = "testing..."
00839 
00840     print "    Value at 1", rbDict.get (1, "Default")
00841     print "    Value at 2", rbDict.get (2, "Default")
00842     print "    Value at 99", rbDict.get (99, "Default")
00843     print "    Keys:", rbDict.keys()
00844     print "    values:", rbDict.values()
00845     print "    Items:", rbDict.items()
00846 
00847     if rbDict.nodes() != rbDict.nodesByTraversal():
00848         print "node lists don't match"
00849 
00850     # convert our RBDict to a dictionary-display,
00851     # evaluate it (creating a dictionary), and build a new RBDict
00852     # from it in reverse order.
00853     revDict = RBDict(eval(str(rbDict)),lambda x, y: cmp(y,x))
00854     print "    " + str(revDict)
00855     print
00856 
00857 
00858 if __name__ == "__main__":
00859 
00860     import sys
00861 
00862     if len(sys.argv) <= 1:
00863         testRBlist()
00864         testRBdict()
00865     sys.exit(0)
00866 
00867 
00868 # end of file.
00869 
00870 

© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."

Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.

122,241 lines of code and growing...