195 lines
3.0 KiB
Ruby
195 lines
3.0 KiB
Ruby
|
# This file contains the Ruby code from book of
|
||
|
# "Data Structures and Algorithms
|
||
|
# with Object-Oriented Design Patterns in Ruby"
|
||
|
# by Bruno R. Preiss.
|
||
|
#
|
||
|
# Copyright (c) 2004 by Bruno R. Preiss, P.Eng. All rights reserved.
|
||
|
|
||
|
class PrePostVisitor < Visitor
|
||
|
|
||
|
abstractmethod :preVisit
|
||
|
|
||
|
abstractmethod :inVisit
|
||
|
|
||
|
abstractmethod :postVisit
|
||
|
|
||
|
alias_method :visit, :inVisit
|
||
|
|
||
|
end
|
||
|
|
||
|
class PreOrder < PrePostVisitor
|
||
|
|
||
|
def initialize(visitor)
|
||
|
super()
|
||
|
@visitor = visitor
|
||
|
end
|
||
|
|
||
|
def preVisit(obj)
|
||
|
@visitor.visit(obj)
|
||
|
end
|
||
|
|
||
|
def inVisit(obj)
|
||
|
end
|
||
|
|
||
|
def postVisit(obj)
|
||
|
end
|
||
|
|
||
|
def done?
|
||
|
@visitor.done?
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
class InOrder < PrePostVisitor
|
||
|
|
||
|
def initialize(visitor)
|
||
|
super()
|
||
|
@visitor = visitor
|
||
|
end
|
||
|
|
||
|
def preVisit(obj)
|
||
|
end
|
||
|
|
||
|
def inVisit(obj)
|
||
|
@visitor.visit(obj)
|
||
|
end
|
||
|
|
||
|
def postVisit(obj)
|
||
|
end
|
||
|
|
||
|
def done?
|
||
|
@visitor.done?
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class PostOrder < PrePostVisitor
|
||
|
|
||
|
def initialize(visitor)
|
||
|
super()
|
||
|
@visitor = visitor
|
||
|
end
|
||
|
|
||
|
def preVisit(obj)
|
||
|
end
|
||
|
|
||
|
def inVisit(obj)
|
||
|
end
|
||
|
|
||
|
def postVisit(obj)
|
||
|
@visitor.visit(obj)
|
||
|
end
|
||
|
|
||
|
def done?
|
||
|
@visitor.done?
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class Tree < Container
|
||
|
|
||
|
def initialize
|
||
|
super
|
||
|
end
|
||
|
|
||
|
abstractmethod :key
|
||
|
|
||
|
abstractmethod :getSubtree
|
||
|
|
||
|
abstractmethod :empty?
|
||
|
|
||
|
abstractmethod :leaf?
|
||
|
|
||
|
abstractmethod :degree
|
||
|
|
||
|
abstractmethod :height
|
||
|
|
||
|
|
||
|
PREVISIT = -1
|
||
|
INVISIT = 0
|
||
|
POSTVISIT = +1
|
||
|
|
||
|
def depthFirstTraversal(&block)
|
||
|
if not empty?
|
||
|
yield (key, PREVISIT)
|
||
|
for i in 0 ... degree
|
||
|
getSubtree(i).depthFirstTraversal(&block)
|
||
|
end
|
||
|
yield (key, POSTVISIT)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def depthFirstTraversalAccept(visitor)
|
||
|
assert { visitor.is_a?(PrePostVisitor) }
|
||
|
depthFirstTraversal do |obj, mode|
|
||
|
break if visitor.done?
|
||
|
case mode
|
||
|
when PREVISIT
|
||
|
visitor.preVisit(obj)
|
||
|
when INVISIT
|
||
|
visitor.inVisit(obj)
|
||
|
when POSTVISIT
|
||
|
visitor.postVisit(obj)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def breadthFirstTraversal
|
||
|
queue = QueueAsLinkedList.new
|
||
|
queue.enqueue(self) if not empty?
|
||
|
while not queue.empty?
|
||
|
head = queue.dequeue
|
||
|
yield head.key
|
||
|
for i in 0 ... head.degree
|
||
|
child = head.getSubtree(i)
|
||
|
queue.enqueue(child) if not child.empty?
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def breadthFirstTraversalAccept(visitor)
|
||
|
breadthFirstTraversal do |obj|
|
||
|
break if visitor.done?
|
||
|
visitor.visit(obj)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def each(&block)
|
||
|
depthFirstTraversal do |obj, mode|
|
||
|
block.call(obj) if mode == PREVISIT
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
class Iterator < Opus8::Iterator
|
||
|
|
||
|
def initialize(tree)
|
||
|
@stack = StackAsLinkedList.new
|
||
|
@stack.push(tree) if not tree.empty?
|
||
|
end
|
||
|
|
||
|
def more?
|
||
|
not @stack.empty?
|
||
|
end
|
||
|
|
||
|
def succ
|
||
|
if more?
|
||
|
top = @stack.pop
|
||
|
i = top.degree - 1
|
||
|
while i >= 0
|
||
|
subtree = top.getSubtree(i)
|
||
|
@stack.push(subtree) if not subtree.empty?
|
||
|
i -= 1
|
||
|
end
|
||
|
result = top.key
|
||
|
else
|
||
|
result = nil
|
||
|
end
|
||
|
return result
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
def iter
|
||
|
Iterator.new(self)
|
||
|
end
|
||
|
|
||
|
end
|