生成具有n个节点的所有二叉树OCaml

时间:2018-10-01 15:57:28

标签: ocaml

我正在尝试编写一个代码,该代码生成具有n个节点的所有二叉树(因此程序必须返回一个列表,我们可以在其中找到具有n个节点的所有不同的二叉树)。

这是我表示二叉树的方式:

type 'a tree = Empty | Node of 'a * 'a tree * 'a tree

所以我试图实现一个函数all_tree : int -> tree list

  1. all_tree 0 = [Empty]
  2. all_tree 1 = [Node('x',Empty,Empty)]
  3. all_tree 2 = [Node('x',Node('x',Empty,Empty),Empty); Node('x',Empty,Node('x',Empty,Empty))]
  4. ...

我尝试了几个主意,但是没有成功。例如,我们可以尝试以下操作:

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*)

此代码不起作用,因为它不会产生所有可能性。

1 个答案:

答案 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之类的东西,甚至可以更明确地调用。实际上,正确命名它可以使您意识到代码有什么问题。通常,如果您不能正确命名一个变量,那是因为您真的不了解它在做什么(甚至是局部变量)。