@@ -336,24 +336,33 @@ def _remove_repair(self) -> None:
336336 self .parent .sibling .color = 0
337337
338338 def check_color_properties (self ) -> bool :
339- """Check if the tree satisfies all Red-Black tree properties.
339+ def check_color_properties (self ) -> bool :
340+ """
341+ Verify that all Red-Black Tree properties are satisfied:
342+ 1. Root node is black
343+ 2. No two consecutive red nodes (red node cannot have red children)
344+ 3. All paths from any node to its leaf descendants have the same number of black nodes
340345
341346 Returns:
342347 True if all properties are satisfied, False otherwise
343348
344349 Examples:
345- >>> tree = RedBlackTree(0)
346- >>> tree = tree.insert(1).insert(-1)
350+ >>> tree = RedBlackTree(10).insert(5).insert(15)
347351 >>> tree.check_color_properties()
348352 True
353+ >>> tree.left.color = 1 # Force invalid state: two consecutive reds
354+ >>> tree.check_color_properties()
355+ False
349356 """
350- # Property 2
351- if self .color :
357+ # Property 1: Root must be black
358+ if self .parent is None and self . color != 0 :
352359 return False
353- # Property 4
360+
361+ # Property 2: No two consecutive red nodes
354362 if not self .check_coloring ():
355363 return False
356- # Property 5
364+
365+ # Property 3: All paths have same black height
357366 return self .black_height () is not None
358367
359368 def check_coloring (self ) -> bool :
@@ -364,18 +373,41 @@ def check_coloring(self) -> bool:
364373 return False
365374 return not (self .right and not self .right .check_coloring ())
366375
367- def black_height (self ) -> int | None :
368- """Calculate the black height of the tree."""
369- if self is None or self .left is None or self .right is None :
370- return 1
371- left = RedBlackTree .black_height (self .left )
372- right = RedBlackTree .black_height (self .right )
373- if left is None or right is None :
374- return None
375- if left != right :
376- return None
377- return left + (1 - self .color )
376+ def black_height (self ) -> int | None :
377+ """
378+ Calculate the black height of the tree and verify consistency
379+ - Black height = number of black nodes from current node to any leaf
380+ - Count includes current node if black and all leaf nodes (None are black)
381+ - Returns None if any path has different black height
378382
383+ Returns:
384+ Black height if consistent, None otherwise
385+
386+ Examples:
387+ >>> tree = RedBlackTree(10, color=0) # Black root
388+ >>> tree.insert(5, color=1) # Red child
389+ >>> tree.black_height() # Paths: [10(black), 5(red), None(black)] = 2
390+ 2 [10(black), None(black)] = 2
391+ """
392+ # Base case: Leaf node (None is always black)
393+ if self is None :
394+ return 1
395+
396+ # Leaf node case (both children are None)
397+ if self .left is None and self .right is None :
398+ # Count: current node (if black) + leaf (black)
399+ return 1 + (1 - self .color ) # 2 if black, 1 if red
400+
401+ # Recursive case: Check both subtrees
402+ left_bh = self .left .black_height () if self .left else 1
403+ right_bh = self .right .black_height () if self .right else 1
404+
405+ # Validate consistency
406+ if left_bh is None or right_bh is None or left_bh != right_bh :
407+ return None # Inconsistent black heights
408+
409+ # Current node's contribution: add 1 if black
410+ return left_bh + (1 - self .color )
379411 def __contains__ (self , label : int ) -> bool :
380412 """Check if the tree contains a label.
381413
0 commit comments