我有这堂课:
class AVLTree
class Node
attr_accessor :value, :height
attr_accessor :left, :right
def initialize(value, height)
@value = value
@height = height
end
end
attr_accessor :root
def initialize
@root = Node.new(nil, 0)
end
# Right rotation of the tree
def right_rotation(node = @root)
begin
root = node.left
node.left = root.right
root.height = node.height
root.right = node
update_subtrees_height(root.right, root.height)
update_subtrees_height(root.left, root.height)
rescue Exception => e
puts "Tree not able to do a right rotation: #{e.message}"
puts e.backtrace.inspect
end
root
end
# Left rotation of the tree
def left_rotation(node = @root)
begin
root = node.right
node.right = root.left
root.height = node.height
root.left = node
update_subtrees_height(root.right, root.height)
update_subtrees_height(root.left, root.height)
rescue Exception => e
puts "Tree not able to do a left rotation: #{e.message}"
puts e.backtrace.inspect
end
root
end
# Update the height of the elements of a sub-tree and all other sub-tree of its side
def update_subtrees_height(node, height)
return if node.nil?
node.height = height + 1
update_subtrees_height(node.left, node.height)
update_subtrees_height(node.right, node.height)
end
def balance_factor(node = @root)
leftSize = node.left.nil? ? 0 : deepest_node(node.left).height
rightSize = node.right.nil? ? 0 : deepest_node(node.right).height
rightSize - leftSize
end
def balance(node = @root)
balanceFactor = balance_factor(node)
return node if balanceFactor <= 1 && balanceFactor >= -1
if balanceFactor > 1
if balance_factor(node.right) < 0
node.right = right_rotation(node.right)
node = left_rotation(node)
else
node = left_rotation(node)
end
else
if balance_factor(node.left) > 0
node.left = right_rotation(node.left)
node = left_rotation(node)
else
node = right_rotation(node)
end
end
end
def print_tree(node = @root)
return if node.nil?
puts "#{node.left.nil? ? 'null' : node.left.value} - #{node.nil? ? 'null' : node.value}(L#{node.height}) - #{node.right.nil? ? 'null' : node.right.value}"
print_tree(node.left)
print_tree(node.right)
end
def deepest_node(node = @root, deepest = @root)
return deepest if node.nil?
if node.height > deepest.height then deepest = node else deepest end
right = deepest_node(node.left, deepest)
left = deepest_node(node.right, deepest)
right.height > left.height ? right : left
end
def insert(value, node = @root)
case value <=> node.value
when -1
if node.left.nil?
node.left = Node.new(value, node.height + 1)
else
insert(value, node.left)
node = balance(node.left)
end
when 1
if node.right.nil?
node.right = Node.new(value, node.height + 1)
else
insert(value, node.right)
node = balance(node)
end
else
node.value = value
end
end
end
我正在做这个测试:
a = AVLTree.new
[1,2,3,4,5].each do |v|
a.insert v
end
a.print_tree a.root
我的预期输出是
1 - 2(H0) - 4
null - 1(H1) - null
3 - 4(H1) - 5
null - 3(H2) - null
null - 5(H2) - null
谁代表下面的树:
2
/ \
1 4
/ \
3 5
我的输出是:
null - 1(H2) - null
调试代码,每次调用行insert
时,我都会在node = balance(node.left)
方法中发现问题。这时我丢失了树的引用。
balance
方法在我的测试中没问题。例如:
当我在树上插入3时,我有
1
\
2
\
3
然后我用节点1调用余额,接收预期的树
2
/ \
1 3
我认为的逻辑是:每当我在树中插入一个值时,我会检查其平衡并在必要时修复它。使用我的insert
方法的递归,我将向上检查树,从插入的节点开始上面一点。在上面的示例中,当我转到节点1并对其进行平衡时,balance
方法将返回一个新节点,其中2与此子树的根一样,旧节点接收该节点。
会发生这种情况,但由于某种原因,AVL树的根节点丢失了对其他节点的引用。任何想法我怎么解决这个问题?
答案 0 :(得分:0)
我还不确定我的问题的原因,但是我以相信更好的方式重新实现了AVL树。它起作用了,我的主要教训是:如果你正在实现一个树,那么创建在节点类本身中操作节点(插入,更新等)的方法是明智的选择!这听起来很明显,但在你第一次这样做时并不那么明显。
以下是我班级的新版本:
class AVLTree
class Node
attr_accessor :right, :left
attr_accessor :key, :height
def initialize(key = nil, height = nil)
@key = key
@height = height
@left = @right = EmptyNode.new
end
def insert(key)
case key <=> @key
when -1
@left = @left.insert(key)
@left.height = self.height + 1
when 0
@value = value
when 1
@right = @right.insert(key)
@right.height = self.height + 1
else
raise TypeError, "Cannot compare #{key} with #{@key}"
end
balance
end
def balance
balanceFactor = balance_factor
return self if balanceFactor >= -1 && balanceFactor <= 1
if balanceFactor > 1
if @right.balance_factor < 0
@right = @right.rotate_right
root = rotate_left
else
root = rotate_left
end
else
if @left.balance_factor > 0
@left = @left.rotate_left
root = rotate_right
else
root = rotate_right
end
end
root
end
def balance_factor
leftSize = @left.nil? ? 0 : deepest_node(@left).height
rightSize = @right.nil? ? 0 : deepest_node(@right).height
rightSize - leftSize
end
def deepest_node(node = self, deepest = self)
return deepest if node.nil?
if node.height > deepest.height then deepest = node else deepest end
right = deepest_node(node.left, deepest)
left = deepest_node(node.right, deepest)
right.height > left.height ? right : left
end
def rotate_left
raise "The node have not right child to do a left rotation" if @right.key.nil?
root = @right
@right = root.left
root.height = @height
root.left = self
root.left.update_height(1)
root.right.update_height(-1)
root
end
def rotate_right
root = @left
@left = root.right
root.height = @height
root.right = self
root.left.update_height(-1)
root.right.update_height(1)
root
end
def update_height(value)
@height += value
@left.update_height(value)
@right.update_height(value)
end
class EmptyNode < Node
def initialize
@key = nil
@height = 0
end
def insert(key)
Node.new(key, 0)
end
def update_height(value)
end
end
end
attr_accessor :root
def initialize
@root = Node::EmptyNode.new
end
def insert(key)
@root = @root.insert(key)
end
def print_tree(node = @root)
return if node.key.nil?
puts "#{node.left.nil? || node.left.key.nil? ? 'null' : node.left.key} - #{node.nil? || node.key.nil? ? 'null' : node.key}(L#{node.height}) - #{node.right.nil? || node.right.key.nil? ? 'null' : node.right.key}"
print_tree(node.left)
print_tree(node.right)
end
# sequence = left, root and right of each sub-tree
def in_order(node = @root, sequence = [])
return sequence if node.key.nil?
in_order(node.left, sequence)
sequence << [node.key, node.height]
in_order(node.right, sequence)
end
end