Skip to content

Commit d6660e5

Browse files
committed
feat: issue #4 reduces CCN of insert_repair() by 65%
1 parent 364f183 commit d6660e5

File tree

1 file changed

+78
-30
lines changed

1 file changed

+78
-30
lines changed

data_structures/binary_tree/red_black_tree.py

Lines changed: 78 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -130,36 +130,9 @@ def _insert_repair(self) -> None:
130130
uncle = self.parent.sibling
131131
if color(uncle) == 0:
132132
coverageList.append(5)
133-
if self.is_left() and self.parent.is_right():
134-
coverageList.append(6)
135-
self.parent.rotate_right()
136-
if self.right:
137-
coverageList.append(7)
138-
self.right._insert_repair()
139-
elif self.is_right() and self.parent.is_left():
140-
coverageList.append(8)
141-
self.parent.rotate_left()
142-
if self.left:
143-
coverageList.append(9)
144-
self.left._insert_repair()
145-
elif self.is_left():
146-
coverageList.append(10)
147-
if self.grandparent:
148-
coverageList.append(11)
149-
self.grandparent.rotate_right()
150-
self.parent.color = 0
151-
if self.parent.right:
152-
coverageList.append(12)
153-
self.parent.right.color = 1
154-
else:
155-
coverageList.append(13)
156-
if self.grandparent:
157-
coverageList.append(14)
158-
self.grandparent.rotate_left()
159-
self.parent.color = 0
160-
if self.parent.left:
161-
coverageList.append(15)
162-
self.parent.left.color = 1
133+
# There are four separate cases when the uncle is black,
134+
# handled in a separate function with explanations
135+
self._insert_case_handler()
163136
else:
164137
coverageList.append(16)
165138
self.parent.color = 0
@@ -169,6 +142,81 @@ def _insert_repair(self) -> None:
169142
self.grandparent.color = 1
170143
self.grandparent._insert_repair()
171144

145+
def _insert_case_handler(self) -> None:
146+
""" When inserting into a red-black tree and finding that the uncle
147+
of the new node is black, there are four separate cases which
148+
must be handled differently in order to rebalance correctly.
149+
Two of them require further traversal, calling insert_repair again.
150+
"""
151+
# Parent right, me left.
152+
# Rotate parent right and insert_repair again (now right-right case).
153+
if self.parent.is_right() and self.is_left():
154+
self._insert_case_right_left()
155+
# Parent left, me right.
156+
# Rotate parent left and insert_repair again (now left-left case).
157+
elif self.parent.is_left() and self.is_right():
158+
self._insert_case_left_right()
159+
# Parent left, me left.
160+
# Rotate grandparent and recolour -> done.
161+
elif self.is_left():
162+
self._insert_case_left_left()
163+
# Parent right, me right.
164+
# Rotate grandparent and recolour -> done.
165+
else:
166+
self._insert_case_right_right()
167+
168+
def _insert_case_right_right(self) -> None:
169+
"""Parent is a right child, node is a right child.
170+
Rotate grandparent left and swap colours of grandparent
171+
and parent. Then we are balanced again.
172+
"""
173+
coverageList.append(13)
174+
if self.grandparent:
175+
coverageList.append(14)
176+
self.grandparent.rotate_left()
177+
self.parent.color = 0
178+
if self.parent.left:
179+
coverageList.append(15)
180+
self.parent.left.color = 1
181+
182+
def _insert_case_left_left(self) -> None:
183+
"""Parent is a left child, node is a left child.
184+
Rotate grandparent right and swap colours of grandparent
185+
and parent. Then we are balanced again.
186+
"""
187+
coverageList.append(10)
188+
if self.grandparent:
189+
coverageList.append(11)
190+
self.grandparent.rotate_right()
191+
self.parent.color = 0
192+
if self.parent.right:
193+
coverageList.append(12)
194+
self.parent.right.color = 1
195+
196+
def _insert_case_right_left(self) -> None:
197+
""" Parent is a right child, node is a left child.
198+
Must rotate parent right so that node becomes
199+
its parent and both are right children, then we can apply
200+
right-right case.
201+
"""
202+
coverageList.append(6)
203+
self.parent.rotate_right()
204+
if self.right:
205+
coverageList.append(7)
206+
self.right._insert_repair()
207+
208+
def _insert_case_left_right(self) -> None:
209+
""" Parent is a left child, node is a right child.
210+
Must rotate parent left so that node becomes
211+
its parent and both are left children, then we can apply
212+
left-left case.
213+
"""
214+
coverageList.append(8)
215+
self.parent.rotate_left()
216+
if self.left:
217+
coverageList.append(9)
218+
self.left._insert_repair()
219+
172220
def remove(self, label: int) -> RedBlackTree:
173221
"""Remove label from this tree."""
174222
if self.label == label:

0 commit comments

Comments
 (0)