OCaml选项值树

时间:2012-05-27 10:46:33

标签: tree ocaml

我的任务是编写一个类型为‘a btree -> ‘a option list的函数,该函数将给定的树以后缀顺序(postorder)存储在‘a option类型的元素列表中。

内部节点将由None表示,值为x的外部节点(叶子)将由Some x表示。

到目前为止,对于树叶很容易,但是如何将它放在'a option list中?

type 'a btree = L of 'a | N of 'a btree * 'a btree ;;

let rec store t =
    match t with
        | L x -> Some x
        | N (a,b) -> None ???   
;;

我知道的第二个匹配案例不正确,但如何解决?

2 个答案:

答案 0 :(得分:3)

如果你看看你的第一个案例,你会发现它也不完全存在;它正在返回'a option,但您希望该函数返回'a option list

显然,你将返回一个列表,所以先修复它:

let rec store = function
  | L x -> [Some x]
  | N (a,b) -> [None] (* ??? *)

现在让我们解决第二种情况;我们想将None附加到输出中,但在此之前,我们需要子树的节点:

let rec store = function
  | L x -> [Some x]
  | N (a,b) -> (store a) @ (store b) @ [None]

@的类型为

'a list -> 'a list -> 'a list

即。它将列表连接在一起。我们想要加入左子树的结果列表,然后是右边的,然后是最后的内部节点的结果。

答案 1 :(得分:3)

如果有人对这种改进感兴趣,可以通过线程化额外的累加器参数,比Len的解决方案更好,性能更好。

我们的想法是从一个带有树并生成列表的函数store : 'a btree -> 'a option list转移到一个函数store' : 'a btree -> 'a option list -> 'a option list,它将树的元素添加到现有的列表作为参数传递。

let rec store' t acc = match t with
  | L x -> Some x :: acc
  | N (a, b) ->
    store' a (store' b (None :: acc))

使用此定义,元素仅在最终结果列表中添加一次,而不是首先用于构建临时store a列表,然后通过(@)第二次附加到最终结果操作

参数顺序很重要,因为在t之前编写acc可以直观地了解列表中的最终元素顺序:t的元素将之前的 > acc中已存在的元素。这允许N案例非常自然地阅读:很容易看到结果首先包含a,然后b,然后是None,然后{ {1}}。

最后,你当然可以用acc

来定义store
store'

习惯上将第一个定义包装在第二个定义中(如果你不想将这个“低级”函数暴露给用户),并赋予它与外部定义相同的名称(它不是不冲突,因为它不是递归的,所以不进入内部范围):

let store t = store' t []

当然,这个定义是否比Len更好“取决于你的评价标准是什么”。 Len的解决方案更短,更易于阅读,并且可以更紧密地映射原始问题。

(你可以通过使用惰性枚举而不是严格的列表来获得两全其美,但那是另一个故事。)