BST property: for each node v with key k , • nodes in left subtree have keys ≤ k • nodes in right subtree have keys ≥ k Have seen simple BST operations : • Search • Minimum • Maximum • Predecessor • Successor • Insert • Delete All take O ( h ) time, h height of BST 1
OK if BST is balanced , then h = O (log n ) Bad if BST is degenerated , then h = Ω( n ) (easy to come up with inputs) Goal now: to take care that BST does not degenerate when inserting or deleting. Many (many many. . . ) approaches, we’re going to see red-black trees 2
Red-black trees Idea simple: a red-black tree is an ordinary BST with one extra bit of storage per node: its colour , red or black Constraining how nodes can be coloured results in (approximate) balancedness of tree Assumption: if either parent, left, or right does not exist, pointer to NULL Regard NULLs as external nodes (leaves) of tree, thus normal nodes are internal 3
A BST is a red-black tree if 1. every node is either red or black 2. the root is black 3. every leaf (NULL) is black 4. red nodes have black children 5. for all nodes, all paths from node to descendant leaves contain same # black nodes 4
Figure 1: red-black tree, according to definition Figure 2: replace NULLs with single “sentinel” NULL( T ) Figure 3: normal drawing style (no NULL ) Definition: the black-height of node v , bh ( v ), is the number of black nodes on any path from v to a leaf, not including v . 5
NULL(T) 6
Lemma. A red-black tree with n internal nodes has height at most 2 log( n + 1). Proof. First show that subtree rooted at any node x contains at least 2bh ( x ) − 1 internal nodes. 7
Induction on height of x Base: (height=0) x is a leaf (NULL( T )), subtree rooted at x contains 2bh ( x ) − 1 = 2 0 − 1 = 1 − 1 = 0 internal nodes Step: Suppose x height > 0 and two children. Each child has black-height of • either bh( x ) (if red), • or bh( x ) − 1 (if black) Case 1: Height of children is less than height of x , thus can apply hypothesis: subtrees rooted in children contain at least 2bh ( x ) − 1 internal nodes each. Thus internal nodes contained in subtree rooted in x is at least 2 · (2bh ( x ) − 1) ≥ 2bh ( x ) − 1 . 8
Case 2: Again, subtrees rooted in children contain at least 2bh ( x ) − 1 − 1 internal nodes each. Thus internal nodes contained in subtree rooted in x is at least 2 · (2bh ( x ) − 1 − 1) + 1 = 2bh ( x ) − 2 + 1 = 2bh ( x ) − 1 . 9
Back to the Lemma. Now let h be height of tree From Property 4 : at least half the nodes on any simple path from root to a leaf (not including root) must be black Thus black-height of root is at least h/ 2, and n ≥ 2 h/ 2 − 1 n + 1 ≥ 2 h/ 2 ⇔ log( n + 1) ≥ h/ 2 ⇔ h ≤ 2 log( n + 1) ⇔ (q.e.d.) Very nice property, since now trivially Search, Minimum, Maximum, Successor, Predecessor in O (log n ) time! How to maintain red-black property? 10
Basic building block to maintain property: rotations left and right rotations Assumptions: left-rotation on x : right child not NULL right-rotation on x : left child not NULL x x y y x A A C y B C A B B C left rotation right rotation 11
7 x 4 11 y 3 6 9 18 2 14 19 12 17 22 20 Left−Rotate(T,x) 7 y 4 18 x 3 6 11 19 2 9 14 22 12 17 20 12
Insertion Can be done in O (log n ) time Suppose we insert new node z • First, ordinary BST insertion of z according to key value (walk down from root, open new leaf). • Then, colour z red . • Finally, call a fixup procedure to restore red-black property. (May have violated red-black property e.g., z ’s parent is red) 13
What can have gone wrong? Reminder: 1. every node is either red or black 2. the root is black 3. every leaf (NULL) is black 4. red nodes have black children 5. for all nodes, all paths from node to descendant leaves contain same # black nodes (1) and (3) certainly still hold (5) as well, since z replaces (black) sentinel, and z is red with sentinel as children (2) and (4) may be violated (because z is red); (2) if z is root, and (4) if z ’s parent is red 14
RB-Insert-Fixup ( T, z ) 1: while colour[parent[ z ]] = red do if parent[ z ] = left[parent[parent[ z ]]] then 2: y ← right[parent[parent[ z ]]] 3: if colour[ y ] = red then 4: colour[parent[ z ]] ← black 5: colour[ y ] ← black 6: colour[parent[parent[ z ]]] ← red 7: z ← parent[parent[ z ]] 8: else 9: if z = right[parent[ z ]] then 10: z ← parent[ z ] 11: Left-Rotate( T, z ) 12: end if 13: colour[parent[ z ]] ← black 14: colour[parent[parent[ z ]]] ← red 15: Right-Rotate( T, parent[parent[ z ]]) 16: end if 17: 15
else 18: same as then with left and right exchanged 19: end if 20: 21: end while 22: colour[root[ T ]] ← black
When RB-Insert-Fixup is called, z is the red node that was added. Claim: at start of each iteration of while loop, 1. node z is red 2. if parent[ z ] is root, then parent[ z ] is black 3. if there is a violation of RB properties, there is at most one violation, either prop 2 or 4 (for the known reasons) (1) and (2) are “little helpers”, (3) is important 16
Recommend
More recommend