3 # This code adapted from C source from
4 # Thomas Niemann's Sorting and Searching Algorithms: A Cookbook
7 # Permission to reproduce this document, in whole or in part, is
8 # given provided the original web site listed below is referenced,
9 # and no additional restrictions apply. Source code, when part of
10 # a software project, may be used freely without reference to the
13 # Adapted by Chris Gonnerman <chris.gonnerman@newcenturycomputers.net>
16 # Adapted by Charles Tolman <ct@acm.org>
17 # inheritance from object class
18 # added RBTreeIter class
19 # added lastNode and prevNode routines to RBTree
20 # added RBList class and associated tests
22 # Trimmed by Guillaume Chazarain <guichaz@gmail.com> to keep only the part
25 __version__
= "1.5-gsh"
34 def __init__(self
, key
= None, value
= None, color
= RED
):
35 self
.left
= self
.right
= self
.parent
= None
41 def __nonzero__(self
):
46 def __init__(self
, cmpfn
=cmp):
47 self
.sentinel
= RBNode()
48 self
.sentinel
.left
= self
.sentinel
.right
= self
.sentinel
49 self
.sentinel
.color
= BLACK
50 self
.sentinel
.nonzero
= 0
51 self
.root
= self
.sentinel
53 # changing the comparison function for an existing tree is dangerous!
59 def rotateLeft(self
, x
):
63 # establish x.right link
65 if y
.left
!= self
.sentinel
:
68 # establish y.parent link
69 if y
!= self
.sentinel
:
72 if x
== x
.parent
.left
:
81 if x
!= self
.sentinel
:
84 def rotateRight(self
, x
):
86 #***************************
87 # rotate node x to right
88 #***************************
92 # establish x.left link
94 if y
.right
!= self
.sentinel
:
97 # establish y.parent link
98 if y
!= self
.sentinel
:
101 if x
== x
.parent
.right
:
110 if x
!= self
.sentinel
:
113 def insertFixup(self
, x
):
114 #************************************
115 # maintain Red-Black tree balance *
116 # after inserting node x *
117 #************************************
119 # check Red-Black properties
121 while x
!= self
.root
and x
.parent
.color
== RED
:
123 # we have a violation
125 if x
.parent
== x
.parent
.parent
.left
:
127 y
= x
.parent
.parent
.right
131 x
.parent
.color
= BLACK
133 x
.parent
.parent
.color
= RED
138 if x
== x
.parent
.right
:
139 # make x a left child
144 x
.parent
.color
= BLACK
145 x
.parent
.parent
.color
= RED
146 self
.rotateRight(x
.parent
.parent
)
149 # mirror image of above code
151 y
= x
.parent
.parent
.left
155 x
.parent
.color
= BLACK
157 x
.parent
.parent
.color
= RED
162 if x
== x
.parent
.left
:
166 x
.parent
.color
= BLACK
167 x
.parent
.parent
.color
= RED
168 self
.rotateLeft(x
.parent
.parent
)
170 self
.root
.color
= BLACK
172 def insertNode(self
, key
, value
):
173 #**********************************************
174 # allocate node for data and insert in tree *
175 #**********************************************
177 # we aren't interested in the value, we just
178 # want the TypeError raised if appropriate
181 # find where node belongs
184 while current
!= self
.sentinel
:
185 # GJB added comparison function feature
186 # slightly improved by JCG: don't assume that ==
187 # is the same as self.__cmp(..) == 0
188 rc
= self
.__cmp
(key
, current
.key
)
193 current
= current
.left
195 current
= current
.right
198 x
= RBNode(key
, value
)
199 x
.left
= x
.right
= self
.sentinel
202 self
.count
= self
.count
+ 1
204 # insert node in tree
206 if self
.__cmp
(key
, parent
.key
) < 0:
216 def deleteFixup(self
, x
):
217 #************************************
218 # maintain Red-Black tree balance *
219 # after deleting node x *
220 #************************************
222 while x
!= self
.root
and x
.color
== BLACK
:
223 if x
== x
.parent
.left
:
228 self
.rotateLeft(x
.parent
)
231 if w
.left
.color
== BLACK
and w
.right
.color
== BLACK
:
235 if w
.right
.color
== BLACK
:
241 w
.color
= x
.parent
.color
242 x
.parent
.color
= BLACK
243 w
.right
.color
= BLACK
244 self
.rotateLeft(x
.parent
)
252 self
.rotateRight(x
.parent
)
255 if w
.right
.color
== BLACK
and w
.left
.color
== BLACK
:
259 if w
.left
.color
== BLACK
:
260 w
.right
.color
= BLACK
265 w
.color
= x
.parent
.color
266 x
.parent
.color
= BLACK
268 self
.rotateRight(x
.parent
)
273 def deleteNode(self
, z
):
274 #****************************
275 # delete node z from tree *
276 #****************************
278 if not z
or z
== self
.sentinel
:
281 if z
.left
== self
.sentinel
or z
.right
== self
.sentinel
:
282 # y has a self.sentinel node as a child
285 # find tree successor with a self.sentinel node as a child
287 while y
.left
!= self
.sentinel
:
290 # x is y's only child
291 if y
.left
!= self
.sentinel
:
296 # remove y from the parent chain
299 if y
== y
.parent
.left
:
314 self
.count
= self
.count
- 1
316 def findNode(self
, key
):
317 #******************************
318 # find node containing data
319 #******************************
321 # we aren't interested in the value, we just
322 # want the TypeError raised if appropriate
327 while current
!= self
.sentinel
:
328 # GJB added comparison function feature
329 # slightly improved by JCG: don't assume that ==
330 # is the same as self.__cmp(..) == 0
331 rc
= self
.__cmp
(key
, current
.key
)
336 current
= current
.left
338 current
= current
.right