Created
August 7, 2012 06:31
-
-
Save timfel/3282404 to your computer and use it in GitHub Desktop.
Modified R/B Bench
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# require 'benchmark' | |
# Algorithm based on "Introduction to Algorithms" by Cormen and others | |
class RedBlackTree | |
class Node | |
attr_accessor :color | |
attr_accessor :key | |
attr_accessor :left | |
attr_accessor :right | |
attr_accessor :parent | |
RED = :red | |
BLACK = :black | |
COLORS = [RED, BLACK]#.freeze | |
def initialize(key, color = RED) | |
raise ArgumentError, "Bad value for color parameter" unless COLORS.include?(color) | |
@color = color | |
@key = key | |
@left = @right = @parent = NilNode.instance | |
end | |
def black? | |
return color == BLACK | |
end | |
def red? | |
return color == RED | |
end | |
end | |
class NilNode < Node | |
class << self | |
private :new | |
# it's not thread safe | |
def instance | |
@instance ||= new# begin | |
# def instance | |
# return @instance | |
# end | |
# new | |
# end | |
end | |
end | |
def initialize | |
self.color = BLACK | |
self.key = 0 | |
self.left = nil | |
self.right = nil | |
self.parent = nil | |
end | |
def nil? | |
return true | |
end | |
end | |
include Enumerable | |
attr_accessor :root | |
attr_accessor :size | |
def initialize | |
self.root = NilNode.instance | |
self.size = 0 | |
end | |
def add(key) | |
insert(Node.new(key)) | |
end | |
def insert(x) | |
insert_helper(x) | |
x.color = Node::RED | |
while x != root && x.parent.color == Node::RED | |
if x.parent == x.parent.parent.left | |
y = x.parent.parent.right | |
if !y.nil? && y.color == Node::RED | |
x.parent.color = Node::BLACK | |
y.color = Node::BLACK | |
x.parent.parent.color = Node::RED | |
x = x.parent.parent | |
else | |
if x == x.parent.right | |
x = x.parent | |
left_rotate(x) | |
end | |
x.parent.color = Node::BLACK | |
x.parent.parent.color = Node::RED | |
right_rotate(x.parent.parent) | |
end | |
else | |
y = x.parent.parent.left | |
if !y.nil? && y.color == Node::RED | |
x.parent.color = Node::BLACK | |
y.color = Node::BLACK | |
x.parent.parent.color = Node::RED | |
x = x.parent.parent | |
else | |
if x == x.parent.left | |
x = x.parent | |
right_rotate(x) | |
end | |
x.parent.color = Node::BLACK | |
x.parent.parent.color = Node::RED | |
left_rotate(x.parent.parent) | |
end | |
end | |
end | |
root.color = Node::BLACK | |
end | |
def <<(x) | |
insert(x) | |
end | |
# alias << insert | |
def delete(z) | |
y = (z.left.nil? || z.right.nil?) ? z : successor(z) | |
x = y.left.nil? ? y.right : y.left | |
x.parent = y.parent | |
if y.parent.nil? | |
self.root = x | |
else | |
if y == y.parent.left | |
y.parent.left = x | |
else | |
y.parent.right = x | |
end | |
end | |
z.key = y.key if y != z | |
if y.color == Node::BLACK | |
delete_fixup(x) | |
end | |
self.size -= 1 | |
return y | |
end | |
def minimum(x = root) | |
while !x.left.nil? | |
x = x.left | |
end | |
return x | |
end | |
def maximum(x = root) | |
while !x.right.nil? | |
x = x.right | |
end | |
return x | |
end | |
def successor(x) | |
if !x.right.nil? | |
return minimum(x.right) | |
end | |
y = x.parent | |
while !y.nil? && x == y.right | |
x = y | |
y = y.parent | |
end | |
return y | |
end | |
def predecessor(x) | |
if !x.left.nil? | |
return maximum(x.left) | |
end | |
y = x.parent | |
while !y.nil? && x == y.left | |
x = y | |
y = y.parent | |
end | |
return y | |
end | |
def inorder_walk(x = root) | |
x = self.minimum | |
while !x.nil? | |
yield x.key | |
x = successor(x) | |
end | |
end | |
alias each inorder_walk | |
def reverse_inorder_walk(x = root) | |
x = self.maximum | |
while !x.nil? | |
yield x.key | |
x = predecessor(x) | |
end | |
end | |
alias reverse_each reverse_inorder_walk | |
def search(key, x = root) | |
while !x.nil? && x.key != key | |
if key < x.key | |
x = x.left | |
else | |
x = x.right | |
end | |
end | |
return x | |
end | |
def empty? | |
return self.root.nil? | |
end | |
def black_height(x = root) | |
height = 0 | |
while !x.nil? | |
x = x.left | |
height +=1 if x.nil? || x.black? | |
end | |
return height | |
end | |
private | |
def left_rotate(x) | |
raise "x.right is nil!" if x.right.nil? | |
y = x.right | |
x.right = y.left | |
y.left.parent = x if !y.left.nil? | |
y.parent = x.parent | |
if x.parent.nil? | |
self.root = y | |
else | |
if x == x.parent.left | |
x.parent.left = y | |
else | |
x.parent.right = y | |
end | |
end | |
y.left = x | |
x.parent = y | |
end | |
def right_rotate(x) | |
raise "x.left is nil!" if x.left.nil? | |
y = x.left | |
x.left = y.right | |
y.right.parent = x if !y.right.nil? | |
y.parent = x.parent | |
if x.parent.nil? | |
self.root = y | |
else | |
if x == x.parent.left | |
x.parent.left = y | |
else | |
x.parent.right = y | |
end | |
end | |
y.right = x | |
x.parent = y | |
end | |
def insert_helper(z) | |
y = NilNode.instance | |
x = root | |
while !x.nil? | |
y = x | |
if z.key < x.key | |
x = x.left | |
else | |
x = x.right | |
end | |
end | |
z.parent = y | |
if y.nil? | |
self.root = z | |
else | |
if z.key < y.key | |
y.left = z | |
else | |
y.right = z | |
end | |
end | |
self.size += 1 | |
end | |
def delete_fixup(x) | |
while x != root && x.color == Node::BLACK | |
if x == x.parent.left | |
w = x.parent.right | |
if w.color == Node::RED | |
w.color = Node::BLACK | |
x.parent.color = Node::RED | |
left_rotate(x.parent) | |
w = x.parent.right | |
end | |
if w.left.color == Node::BLACK && w.right.color == Node::BLACK | |
w.color = Node::RED | |
x = x.parent | |
else | |
if w.right.color == Node::BLACK | |
w.left.color = Node::BLACK | |
w.color = Node::RED | |
right_rotate(w) | |
w = x.parent.right | |
end | |
w.color = x.parent.color | |
x.parent.color = Node::BLACK | |
w.right.color = Node::BLACK | |
left_rotate(x.parent) | |
x = root | |
end | |
else | |
w = x.parent.left | |
if w.color == Node::RED | |
w.color = Node::BLACK | |
x.parent.color = Node::RED | |
right_rotate(x.parent) | |
w = x.parent.left | |
end | |
if w.right.color == Node::BLACK && w.left.color == Node::BLACK | |
w.color = Node::RED | |
x = x.parent | |
else | |
if w.left.color == Node::BLACK | |
w.right.color = Node::BLACK | |
w.color = Node::RED | |
left_rotate(w) | |
w = x.parent.left | |
end | |
w.color = x.parent.color | |
x.parent.color = Node::BLACK | |
w.left.color = Node::BLACK | |
right_rotate(x.parent) | |
x = root | |
end | |
end | |
end | |
x.color = Node::BLACK | |
end | |
end | |
def rbt_bm | |
n = 100_000 | |
a1 = []; n.times { a1 << 63106 | |
#rand(999_999) | |
} | |
a2 = []; n.times { a2 << 172958 | |
#rand(999_999) | |
} | |
start = Time.now | |
tree = RedBlackTree.new | |
n.times {|i| tree.add(i) } | |
n.times { tree.delete(tree.root) } | |
tree = RedBlackTree.new | |
a1.each {|e| tree.add(e) } | |
a2.each {|e| tree.search(e) } | |
tree.inorder_walk {|key| key + 1 } | |
tree.reverse_inorder_walk {|key| key + 1 } | |
n.times { tree.minimum } | |
n.times { tree.maximum } | |
return Time.now - start | |
end | |
N = (ARGV[0] || 10).to_i | |
N.times do | |
puts rbt_bm.to_f | |
# puts "GC.count = #{GC.count}" if GC.respond_to?(:count) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment