我正在尝试编写一个代码,该代码生成具有n
个节点的所有二叉树(因此程序必须返回一个列表,我们可以在其中找到具有n
个节点的所有不同的二叉树)。
这是我表示二叉树的方式:
type 'a tree = Empty | Node of 'a * 'a tree * 'a tree
所以我试图实现一个函数all_tree : int -> tree list
:
all_tree 0 = [Empty]
all_tree 1 = [Node('x',Empty,Empty)]
all_tree 2 = [Node('x',Node('x',Empty,Empty),Empty); Node('x',Empty,Node('x',Empty,Empty))]
我尝试了几个主意,但是没有成功。例如,我们可以尝试以下操作:
let rec all_tree result = function
|0 -> r
|s -> all_tree ((List.map (fun i -> Node('x',i,Empty)) result)@(List.map (fun i -> Node('x',Empty,i)) result) ) (s-1)
in all_tree [Empty] (*some number*)
此代码不起作用,因为它不会产生所有可能性。
答案 0 :(得分:1)
这是一个可能的答案。
let rec all_trees = function
| 0 -> [Empty]
| n ->
let result = ref [] in
for i = 0 to n-1 do
let left_side = all_trees i
and right_side = all_trees (n-1-i) in
List.iter
(fun left_tree ->
List.iter
(fun right_tree ->
result := (Node('x', left_tree, right_tree)) :: (!result)
)
right_side
)
left_side
done;
!result
;;
这非常简单:n个节点大于0的树是顶部具有1个节点的树,然后下面的n-1个节点在左侧的某个数字和右侧的某个数字之间划分。因此,我们通过左侧所有可能数量的值从0到n-1循环i,而n-i-1将成为右侧的节点数量。我们递归调用all_trees
以获取具有i和n-i-1节点的树,并简单地对其进行汇总。
请注意,这是一个非常差的实现。它具有递归函数应避免的所有内容。查看类似this page on recursive implementations of the Fibonacci sequence之类的内容以了解如何进行改进(要做的第一件事就是缓存结果,而不是多次重复计算相同的结果)。
我确实同意该问题的意见,尽管写打印机将是该项目的第一步,因为必须阅读诸如[Node ('x', Node ('x', Empty, Node ('x', Node ('x', Empty, Empty), Empty)), Empty);
之类的混乱内容实在令人讨厌。更好地命名变量还可以使人们更轻松地阅读您的代码,并增加有人帮助您的机会。通常,当人们为您提供有关如何正确提出问题的建议时,听听他们的意见将使您现在和将来的问题都更容易获得答案。例如,在我自己的代码中,我使用i
作为循环索引。在我编写代码时,这对我来说很有意义,但是当您阅读代码时,也许您会更喜欢读诸如left_side_nodes
之类的东西,这将使该变量应具有的作用显而易见做。在您自己的场景中是相同的:您可以调用i
之类的subtree
之类的东西,甚至可以更明确地调用。实际上,正确命名它可以使您意识到代码有什么问题。通常,如果您不能正确命名一个变量,那是因为您真的不了解它在做什么(甚至是局部变量)。