Binary 将二叉树展平到列表(有序)
我正在尝试实现一种算法,该算法将树作为输入,并返回一个列表,其中所有值的顺序都正确(从上到下,每行从左到右),但我遇到了问题。无序操作的简单方法是减少整个列表,其中每个节点都附加到累积列表中 这是我编写的代码,用于简化树(用elixir编写),其中每个节点都有一个左右分支,可以是另一个节点,也可以是nil: def reduce(nil, op, init), do: init def reduce({:node, n, left, right}, op, init) do reduce(right, op, reduce(left, op, op.(n, init))) end def reduce(nil,op,init),do:init def reduce({:node,n,left,right},op,init)do reduce(右,op,reduce(左,op,op.(n,init))) 结束 这样调用以获取树(但顺序错误): 结果=减少(树,fn(节点,acc)->[acc |节点]结束,[])Binary 将二叉树展平到列表(有序),binary,Binary,我正在尝试实现一种算法,该算法将树作为输入,并返回一个列表,其中所有值的顺序都正确(从上到下,每行从左到右),但我遇到了问题。无序操作的简单方法是减少整个列表,其中每个节点都附加到累积列表中 这是我编写的代码,用于简化树(用elixir编写),其中每个节点都有一个左右分支,可以是另一个节点,也可以是nil: def reduce(nil, op, init), do: init def reduce({:node, n, left, right}, op, init) do
有什么提示吗?一般来说,您可以在结果列表中调用
&Enum.reverse/1
。由于在erlang中构造列表的方式的性质,您会发现很多算法都是在幕后完成这项工作的。我认为甚至&Enum.map/2
都使用它
除此之外,还有一种更简单的方法可以使用函数头编写功能。我相信您正在寻找一种按序遍历树的方法,其中每个访问的节点都被添加到列表中,但是您可以很容易地修改它,以包括后序遍历和前序遍历。这里有一个模块,其中包含您正在寻找的map/reduce函数
defmodule Tree do
# This just uses the reduce functions defined below to create a map.
def map_inorder(root) do
root
|> reduce_inorder([], fn val, acc ->
[val | acc]
end)
|> Enum.reverse()
end
# This is the core functionality of the function for an inorder traversal
# It processes the left subtree then calls the reducer on the root node
# and then processes the right subtree.
def reduce_inorder({:node, val, left, right}, acc, fun) do
left_subtree = reduce_inorder(left, acc, fun)
visit_root = fun.(val, left_subtree)
reduce_inorder(right, visit_root, fun)
end
# Nil means that you've reached a leaf. There's nothing else to process
def reduce_inorder(nil, acc, _fun) do
acc
end
# Node does not match the spec you have for the record. Return an error
def reduce_inorder(_other, _, _) do
:malformed_node
end
end
二叉树遍历算法非常容易理解。这里有一篇文章很好地解释了它们
干杯
编辑
我意识到你说的是广度优先搜索(BFS),它是一种完全不同的算法。基本上,您必须将节点推入队列而不是堆栈中,这是前序/后序/顺序遍历算法所做的
BFS确保在树的相同深度内按从左到右的顺序处理所有节点。通常,从根节点开始,它是队列中唯一的节点。处理该节点,然后按顺序将其左右子节点推入队列,然后在新队列上重复。幸运的是,我记得erlang有一个:queue
模块,这使它更容易实现。您可以在下面找到代码:
defmodule Tree do
def map_tree(root) do
root
|> reduce_tree([], fn val, acc ->
[val | acc]
end)
|> Enum.reverse()
end
def reduce_tree(root, acc, reducer) do
:queue.new()
|> queue_in(root)
|> process_queue(acc, reducer)
end
def process_queue(queue, acc, reducer) do
case queue_out(queue) do
{{:value, {:node, val, left, right}}, popped} ->
# Process the head of the queue which is the next item in the traversal
new_acc = reducer.(val, acc)
# Push in the left then right so that they are processed in that order
# and so that they are processsed behind earlier nodes that have been
# found
popped
|> queue_in(left)
|> queue_in(right)
|> process_queue(new_acc, reducer)
_other ->
# Your queue is empty. Return the reduction
acc
end
end
# These are convenience methods. If the value being pushed in is nil then
# ignore it so that it is not processed
def queue_in(queue, nil) do
queue
end
def queue_in(queue, val) do
:queue.in(val, queue)
end
def queue_out(queue) do
:queue.out(queue)
end
end
这种方法的优点在于它具有尾部递归
我希望这有帮助。这里有一篇关于BFS的好文章:
根据一般经验,您可以在结果列表中调用
&Enum.reverse/1
。由于在erlang中构造列表的方式的性质,您会发现很多算法都是在幕后完成这项工作的。我认为甚至&Enum.map/2
都使用它
除此之外,还有一种更简单的方法可以使用函数头编写功能。我相信您正在寻找一种按序遍历树的方法,其中每个访问的节点都被添加到列表中,但是您可以很容易地修改它,以包括后序遍历和前序遍历。这里有一个模块,其中包含您正在寻找的map/reduce函数
defmodule Tree do
# This just uses the reduce functions defined below to create a map.
def map_inorder(root) do
root
|> reduce_inorder([], fn val, acc ->
[val | acc]
end)
|> Enum.reverse()
end
# This is the core functionality of the function for an inorder traversal
# It processes the left subtree then calls the reducer on the root node
# and then processes the right subtree.
def reduce_inorder({:node, val, left, right}, acc, fun) do
left_subtree = reduce_inorder(left, acc, fun)
visit_root = fun.(val, left_subtree)
reduce_inorder(right, visit_root, fun)
end
# Nil means that you've reached a leaf. There's nothing else to process
def reduce_inorder(nil, acc, _fun) do
acc
end
# Node does not match the spec you have for the record. Return an error
def reduce_inorder(_other, _, _) do
:malformed_node
end
end
二叉树遍历算法非常容易理解。这里有一篇文章很好地解释了它们
干杯
编辑
我意识到你说的是广度优先搜索(BFS),它是一种完全不同的算法。基本上,您必须将节点推入队列而不是堆栈中,这是前序/后序/顺序遍历算法所做的
BFS确保在树的相同深度内按从左到右的顺序处理所有节点。通常,从根节点开始,它是队列中唯一的节点。处理该节点,然后按顺序将其左右子节点推入队列,然后在新队列上重复。幸运的是,我记得erlang有一个:queue
模块,这使它更容易实现。您可以在下面找到代码:
defmodule Tree do
def map_tree(root) do
root
|> reduce_tree([], fn val, acc ->
[val | acc]
end)
|> Enum.reverse()
end
def reduce_tree(root, acc, reducer) do
:queue.new()
|> queue_in(root)
|> process_queue(acc, reducer)
end
def process_queue(queue, acc, reducer) do
case queue_out(queue) do
{{:value, {:node, val, left, right}}, popped} ->
# Process the head of the queue which is the next item in the traversal
new_acc = reducer.(val, acc)
# Push in the left then right so that they are processed in that order
# and so that they are processsed behind earlier nodes that have been
# found
popped
|> queue_in(left)
|> queue_in(right)
|> process_queue(new_acc, reducer)
_other ->
# Your queue is empty. Return the reduction
acc
end
end
# These are convenience methods. If the value being pushed in is nil then
# ignore it so that it is not processed
def queue_in(queue, nil) do
queue
end
def queue_in(queue, val) do
:queue.in(val, queue)
end
def queue_out(queue) do
:queue.out(queue)
end
end
这种方法的优点在于它具有尾部递归
我希望这有帮助。这里有一篇关于BFS的好文章: