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 # http://epaperpress.com
15 # Adapted by Chris Gonnerman <chris.gonnerman@newcenturycomputers.net>
18 # Adapted by Charles Tolman <ct@acm.org>
19 # inheritance from object class
20 # added RBTreeIter class
21 # added lastNode and prevNode routines to RBTree
22 # added RBList class and associated tests
24 # Trimmed by Guillaume Chazarain <guichaz@gmail.com> to keep only the part
27 __version__
= "1.5-gsh"
36 def __init__(self
, key
= None, value
= None, color
= RED
):
37 self
.left
= self
.right
= self
.parent
= None
43 def __nonzero__(self
):
48 def __init__(self
, cmpfn
=cmp):
49 self
.sentinel
= RBNode()
50 self
.sentinel
.left
= self
.sentinel
.right
= self
.sentinel
51 self
.sentinel
.color
= BLACK
52 self
.sentinel
.nonzero
= 0
53 self
.root
= self
.sentinel
55 # changing the comparison function for an existing tree is dangerous!
61 def rotateLeft(self
, x
):
65 # establish x.right link
67 if y
.left
!= self
.sentinel
:
70 # establish y.parent link
71 if y
!= self
.sentinel
:
74 if x
== x
.parent
.left
:
83 if x
!= self
.sentinel
:
86 def rotateRight(self
, x
):
88 #***************************
89 # rotate node x to right
90 #***************************
94 # establish x.left link
96 if y
.right
!= self
.sentinel
:
99 # establish y.parent link
100 if y
!= self
.sentinel
:
103 if x
== x
.parent
.right
:
112 if x
!= self
.sentinel
:
115 def insertFixup(self
, x
):
116 #************************************
117 # maintain Red-Black tree balance *
118 # after inserting node x *
119 #************************************
121 # check Red-Black properties
123 while x
!= self
.root
and x
.parent
.color
== RED
:
125 # we have a violation
127 if x
.parent
== x
.parent
.parent
.left
:
129 y
= x
.parent
.parent
.right
133 x
.parent
.color
= BLACK
135 x
.parent
.parent
.color
= RED
140 if x
== x
.parent
.right
:
141 # make x a left child
146 x
.parent
.color
= BLACK
147 x
.parent
.parent
.color
= RED
148 self
.rotateRight(x
.parent
.parent
)
151 # mirror image of above code
153 y
= x
.parent
.parent
.left
157 x
.parent
.color
= BLACK
159 x
.parent
.parent
.color
= RED
164 if x
== x
.parent
.left
:
168 x
.parent
.color
= BLACK
169 x
.parent
.parent
.color
= RED
170 self
.rotateLeft(x
.parent
.parent
)
172 self
.root
.color
= BLACK
174 def insertNode(self
, key
, value
):
175 #**********************************************
176 # allocate node for data and insert in tree *
177 #**********************************************
179 # we aren't interested in the value, we just
180 # want the TypeError raised if appropriate
183 # find where node belongs
186 while current
!= self
.sentinel
:
187 # GJB added comparison function feature
188 # slightly improved by JCG: don't assume that ==
189 # is the same as self.__cmp(..) == 0
190 rc
= self
.__cmp
(key
, current
.key
)
195 current
= current
.left
197 current
= current
.right
200 x
= RBNode(key
, value
)
201 x
.left
= x
.right
= self
.sentinel
204 self
.count
= self
.count
+ 1
206 # insert node in tree
208 if self
.__cmp
(key
, parent
.key
) < 0:
218 def deleteFixup(self
, x
):
219 #************************************
220 # maintain Red-Black tree balance *
221 # after deleting node x *
222 #************************************
224 while x
!= self
.root
and x
.color
== BLACK
:
225 if x
== x
.parent
.left
:
230 self
.rotateLeft(x
.parent
)
233 if w
.left
.color
== BLACK
and w
.right
.color
== BLACK
:
237 if w
.right
.color
== BLACK
:
243 w
.color
= x
.parent
.color
244 x
.parent
.color
= BLACK
245 w
.right
.color
= BLACK
246 self
.rotateLeft(x
.parent
)
254 self
.rotateRight(x
.parent
)
257 if w
.right
.color
== BLACK
and w
.left
.color
== BLACK
:
261 if w
.left
.color
== BLACK
:
262 w
.right
.color
= BLACK
267 w
.color
= x
.parent
.color
268 x
.parent
.color
= BLACK
270 self
.rotateRight(x
.parent
)
275 def deleteNode(self
, z
):
276 #****************************
277 # delete node z from tree *
278 #****************************
280 if not z
or z
== self
.sentinel
:
283 if z
.left
== self
.sentinel
or z
.right
== self
.sentinel
:
284 # y has a self.sentinel node as a child
287 # find tree successor with a self.sentinel node as a child
289 while y
.left
!= self
.sentinel
:
292 # x is y's only child
293 if y
.left
!= self
.sentinel
:
298 # remove y from the parent chain
301 if y
== y
.parent
.left
:
316 self
.count
= self
.count
- 1
318 def findNode(self
, key
):
319 #******************************
320 # find node containing data
321 #******************************
323 # we aren't interested in the value, we just
324 # want the TypeError raised if appropriate
329 while current
!= self
.sentinel
:
330 # GJB added comparison function feature
331 # slightly improved by JCG: don't assume that ==
332 # is the same as self.__cmp(..) == 0
333 rc
= self
.__cmp
(key
, current
.key
)
338 current
= current
.left
340 current
= current
.right