Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

RedBlackTree: eager rebalance after insert

Change internal rebalance timing.  Do convert (b (r r)) -> (r (b b)) to
make balance of tree be perfect after insert.  Before this commit, the
above convert run at the next insert.

It includes related 4 updates for the test.  2 tests for delete indicate
that the balance of the tree is better than before.  Other 2 tests for
insert indicate that the balance of the tree is better than before at
the first insert, and the balance is the same as before at the second
insert.
  • Loading branch information...
commit 713e4b7c0ab315cceb0a39df85dbbf44cd565550 1 parent 40df91d
@nahi authored
Showing with 31 additions and 31 deletions.
  1. +25 −25 lib/red_black_tree.rb
  2. +6 −6 test/test_red_black_tree.rb
View
50 lib/red_black_tree.rb
@@ -67,18 +67,18 @@ def insert(key, value)
case key <=> @key
when -1
@left = @left.insert(key, value)
- if black? and @left.red? and !@left.children_both_black?
+ if black? and @right.black? and @left.red? and !@left.children_both_black?
ret = rebalance_for_left_insert
end
when 0
@value = value
when 1
@right = @right.insert(key, value)
- if black? and @right.red? and !@right.children_both_black?
+ if black? and @left.black? and @right.red? and !@right.children_both_black?
ret = rebalance_for_right_insert
end
end
- ret
+ ret.pullup_red
end
# returns value
@@ -304,40 +304,40 @@ def rotate_right
root
end
+ # Pull up red nodes
+ # (b (A C)) where A and C are RED --> (B (a c))
+ #
+ # b B
+ # / \ -> / \
+ # A C a c
+ #
+ def pullup_red
+ if black? and @left.red? and @right.red?
+ @left.color = @right.color = :BLACK
+ self.color = :RED
+ end
+ self
+ end
+
private
# trying to rebalance when the left sub-tree is 1 level higher than the right
# precondition: self is black and @left is red
def rebalance_for_left_insert
- ret = self
- if @right.red?
- # pull-up red nodes and let the parent rebalance (see precondition)
- @color = :RED
- @left.color = @right.color = :BLACK
- else
- # move 1 black from the left to the right by single/double rotation
- if @left.right.red?
- @left = @left.rotate_left
- end
- ret = rotate_right
+ # move 1 black from the left to the right by single/double rotation
+ if @left.right.red?
+ @left = @left.rotate_left
end
- ret
+ rotate_right
end
# trying to rebalance when the right sub-tree is 1 level higher than the left
# See rebalance_for_left_insert.
def rebalance_for_right_insert
- ret = self
- if @left.red?
- @color = :RED
- @left.color = @right.color = :BLACK
- else
- if @right.left.red?
- @right = @right.rotate_right
- end
- ret = rotate_left
+ if @right.left.red?
+ @right = @right.rotate_right
end
- ret
+ rotate_left
end
def delete_self
View
12 test/test_red_black_tree.rb
@@ -51,7 +51,7 @@ def test_tree_rotate_RL
h['c'] = 6
assert_equal '(b a (g (d c) h))', h.dump_sexp
h['e'] = 6
- assert_equal '(b a (g (d c e) h))', h.dump_sexp
+ assert_equal '(d (b a c) (g e h))', h.dump_sexp
h['f'] = 6
assert_equal '(d (b a c) (g (e - f) h))', h.dump_sexp
end
@@ -67,7 +67,7 @@ def test_tree_rotate_LR
h['0'] = 7
h['c'] = 8
h['e'] = 9
- assert_equal '(g (b (a 0) (d c e)) (h - i))', h.dump_sexp
+ assert_equal '(d (b (a 0) c) (g e (h - i)))', h.dump_sexp
h['f'] = 10
assert_equal '(d (b (a 0) c) (g (e - f) (h - i)))', h.dump_sexp
end
@@ -247,9 +247,9 @@ def test_delete_node_right
h['f'] = 8
h['h'] = 9
h['j'] = 10
- assert_equal '(c (b a) (g (e d f) (i h j)))', h.dump_sexp
+ assert_equal '(e (c (b a) d) (g f (i h j)))', h.dump_sexp
h.delete('g')
- assert_equal '(c (b a) (h (e d f) (i - j)))', h.dump_sexp
+ assert_equal '(e (c (b a) d) (h f (i - j)))', h.dump_sexp
end
def test_delete_node_left
@@ -264,9 +264,9 @@ def test_delete_node_left
h['e'] = 8
h['c'] = 9
h['a'] = 10
- assert_equal '(h (d (b a c) (f e g)) (i - j))', h.dump_sexp
+ assert_equal '(f (d (b a c) e) (h g (i - j)))', h.dump_sexp
h.delete('d')
- assert_equal '(h (e (b a c) (f - g)) (i - j))', h.dump_sexp
+ assert_equal '(f (b a (e c)) (h g (i - j)))', h.dump_sexp
end
def test_delete_root
Please sign in to comment.
Something went wrong with that request. Please try again.