- 参考
- http://www.geocities.jp/h2fujimura/mutter/tree/red-black-tree.html
class RedBlackTree
class Node
def initialize( key, value, is_red = false, left = nil, right = nil, is_nilnode = false )
@key = key
@value = value
@is_red = is_red
if is_nilnode
@is_nilnode = true
@left = nil
@right = nil
@parent = nil
return
end
@parent = nil
self.left = left || self.class.new_nilnode
self.right = right || self.class.new_nilnode
@is_nilnode = false
end
def self.new_nilnode
return new( 'NIL', nil, false, nil, nil, true )
end
attr_accessor :key, :value, :is_red, :left, :right, :parent, :is_nilnode
def nilnode?; @is_nilnode; end
def left=( left )
@left = left
left.parent = self
end
def right=( right )
@right = right
right.parent = self
end
def set( other )
[:@key, :@value, :@is_red, :@left, :@right, :@is_nilnode].each do |sym|
instance_variable_set( sym, other.instance_variable_get( sym ) )
end
unless other.nilnode?
other.left.parent = self
other.right.parent = self
end
end
def left?
parent.left == self
end
def right?
parent.right == self
end
def inside?
( left? && parent.right? ) || ( right? && parent.left? )
end
def brother
left? ? parent.right : parent.left
end
def grandparent
parent.parent
end
def uncle
parent.brother
end
def root?
!@parent
end
def valid?( parent = nil, count = 0, is_left = false )
return false if root? && red?
return false if parent != @parent
return false if parent && parent.red? && red?
if !root?
return false if is_left != left?
return false if !is_left != right?
return false if brother.brother != self
if !nilnode?
return false if left? && @key >= parent.key
return false if right? && @key < parent.key
end
end
if nilnode?
return false if red?
return count + 1
end
count += 1 if black?
left_count = @left.valid?( self, count, true )
return false if !left_count
right_count = @right.valid?( self, count, false )
return false if !right_count
return false if left_count != right_count
return left_count
end
def rotate_left
a = self
b = left
c = right
d = c.left
e = c.right
c_copy = self.class.new_nilnode.set( c )
c.set( d )
c_copy.left = self.class.new_nilnode.set( a )
a.set( c_copy )
return c_copy.left
end
def rotate_right
a = self
b = left
c = right
d = b.left
e = b.right
b_copy = self.class.new_nilnode.set( b )
b.set( e )
b_copy.right = self.class.new_nilnode.set( a )
a.set( b_copy )
return b_copy.right
end
def rotate_outside
left? ? rotate_left : rotate_right
end
def each
return if nilnode?
@left.each{|v| yield v } if @left
yield [key, value]
@right.each{|v| yield v } if @right
end
def inspect( level = 0 )
ret = ' ' * level
ret += (red? ? '○' : '●') + ' '
ret += key.inspect
ret += "\n"
return ret.chomp if nilnode?
ret += @left.inspect( level + 2 ).chomp + "\n"
ret += @right.inspect( level + 2 ).chomp + "\n"
return ret.chomp
end
def red?; @is_red; end
def black?; !@is_red; end
def to_red; @is_red = true; end
def to_black; @is_red = false; end
end
def initialize
@tree = Node.new_nilnode
end
attr_reader :tree
def []( key )
node = search( key )
return nil if node.nilnode?
node.value
end
def []=( key, value )
node = search( key )
unless node.nilnode?
node.value = value
return value
end
node.set( Node.new( key, value, true ) )
insert_adjust( node )
return value
end
def each
@tree.each{|v| yield v }
end
include Enumerable
def inspect
'{' + map{|key,value|
key.inspect+'=>'+value.inspect}.join(', ') + '}'
end
def search( key )
node = @tree
loop do
return node if node.nilnode?
return node if node.key == key
if key < node.key
node = node.left
else
node = node.right
end
end
end
def insert_adjust( node )
if node.root?
node.to_black
return
end
if node.parent.black?
return
end
if node.uncle.red?
node.parent.to_black
node.uncle.to_black
node.grandparent.to_red
insert_adjust( node.grandparent )
return
end
if node.inside?
node = node.parent.rotate_outside
end
g = node.left? ? node.grandparent.rotate_right : node.grandparent.rotate_left
g.to_red
g.parent.to_black
end
end
hash = RedBlackTree.new
1.upto(20) {|v| hash[v] = v }
p hash.tree
puts hash.tree.valid?