我创建了一个非常简单的节点类,其中包含名称和节点数组。我还创建了一个迭代器类,其下一个方法可以帮助我迭代每个节点和子节点。我需要编写下一个方法,但我不知道最好的方法是什么。
class Node
def initialize(name, nodes
@name = name
@nodes = nodes
end
end
class Iterator
def initialize(node)
@node = node
end
def next
???
end
end
示例:
z = Node.new("z", [])
b = Node.new("b", [z])
c = Node.new("c", [])
parent = Node.new("a", [b, c])
iterator = Iterator.new(parent)
str = ''
next = iterator.next
while next do
str += next.name
next = iterator.next
end
str应该等于“abzc”
有人可以帮我吗?
答案 0 :(得分:6)
如果我建议采用更惯用的方法:
class Node
attr_accessor :name, :children
def initialize(name, children = [ ])
@name = name
@children = children
end
def traverse(&block)
yield self
@children.each { |child| child.traverse(&block) }
end
end
z = Node.new("z")
b = Node.new("b", [z])
c = Node.new("c")
parent = Node.new("a", [b, c])
str = ''
parent.traverse { |node| str += node.name }
puts str
这比btilly的解决方案(也是正确的)有一个好处,因为它不会扩散Iterator对象并吸收内存 - 实际上Iterator从实现中消失了(同时仍然保留了对每个节点执行某些操作的能力)演替)。这更加惯用;更多Ruby-esque。
答案 1 :(得分:0)
在你的迭代器中,如果节点有任何子节点,则next是第一个节点。如果没有,那么你需要“备份”到你跳过的最后一个兄弟。这意味着你需要跟踪已被跳过的兄弟姐妹,以便你可以回到它们。
答案 2 :(得分:0)
以下是一些正在运行的代码,用于演示我认为您正在寻找的内容。
class Node
attr_accessor :name, :nodes
def initialize(name, nodes)
@name = name
@nodes = nodes
end
end
class Iterator
def initialize(node)
@node = node
end
def each_node
yield @node
for node in @node.nodes do
iterator = Iterator.new(node)
iterator.each_node {|next_node|
yield next_node
}
end
end
end
z = Node.new("z", [])
b = Node.new("b", [z])
c = Node.new("c", [])
parent = Node.new("a", [b, c])
iterator = Iterator.new(parent)
str = ''
iterator.each_node {|node|
str += node.name
}
puts str
答案 3 :(得分:0)
通过执行以下操作,我已经能够解决我的问题。但我不喜欢这种方法是我在初始化期间遍历节点而不是在下一个方法中...
class Iterator
def initialize(node)
@node = node
@index = -1
@list = []
traverse(@node)
end
def next
@index += 1
@list[@index]
end
private
def traverse(root)
@list[@list.size] = root
if root.nodes
for n in root.nodes do
traverse(n)
end
end
end
end