Tree OCaml选项值树
我的任务是编写一个类型为Tree OCaml选项值树,tree,ocaml,Tree,Ocaml,我的任务是编写一个类型为'abtree->'的函数,它是一个选项列表,将给定的树存储在一个类型为'a option的元素列表中,以后缀顺序(postfix order) 内部节点将由None表示,值为x的外部节点(叶)将由Some x表示 到目前为止,为叶子做这件事很容易,但是如何将它放在选项列表中呢 type 'a btree = L of 'a | N of 'a btree * 'a btree ;; let rec store t = match t with
'abtree->'的函数,它是一个选项列表
,将给定的树存储在一个类型为'a option
的元素列表中,以后缀顺序(postfix order)
内部节点将由None
表示,值为x
的外部节点(叶)将由Some x
表示
到目前为止,为叶子做这件事很容易,但是如何将它放在选项列表中呢
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 ???
;;
我知道的第二个匹配案例是不正确的,但是如何解决它呢?如果你看第一个案例,你会发现它也不太正确;它正在返回一个选项,但您希望函数返回一个选项列表 很明显,您将返回一个列表,因此首先修复该问题:
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
i、 它将列表连接在一起。我们希望从左子树,然后是右子树,最后是该内部节点的结果加入结果列表。如果有人对这种细化感兴趣,可以通过线程化附加累加器参数,在性能方面比Len的解决方案做得更好
let rec store' t acc = match t with
| L x -> Some x :: acc
| N (a, b) ->
store' a (store' b (None :: acc))
我们的想法是从一个函数存储区:'a btree->'一个选项列表
,它获取一棵树并生成一个列表,移动到一个函数存储区:'a btree->'一个选项列表
,它将树的元素添加到作为参数传递的现有列表中
let rec store' t acc = match t with
| L x -> Some x :: acc
| N (a, b) ->
store' a (store' b (None :: acc))
使用此定义,元素只在最终结果列表中添加一次,而不是首先用于构建临时存储列表,然后通过(@)
操作符将第二次附加到最终结果
参数顺序很重要,因为在acc
之前写入t
可以直观地知道列表中的最终元素顺序:t
的元素将位于acc
中已经存在的元素之前。这使得N
案例的阅读非常自然:很容易看出,结果将首先包含a
,然后是b
,然后是None
,然后是acc
最后,您当然可以根据store'
定义store
:
let store t = store' t []
通常将第一个定义封装在第二个定义中(如果您不想向用户公开此“低级”函数),并将其命名为与外部定义相同的名称(这不会冲突,因为它不是递归的,因此不会进入内部范围):
当然,这个定义是否比Len的定义“更好”取决于你的评价标准是什么。Len的解决方案更短,更容易阅读,并且更接近原始问题
(通过使用惰性枚举而不是严格的列表,您可能会获得这两个方面的最佳效果,但这又是另一回事。)顺便问一下,这是家庭作业吗?如果是这样的话,这并不是一件坏事,但这样说被认为是礼貌的。是的,希望这将是最后一件事:D。我对Ocaml有一些概念是好的,但老实说,这是我以后永远不会使用的东西。你可能会感到惊讶;我在工作中用过很多次,这不是你所说的学术环境。有时候,它正是这份工作的合适工具。我建议你看看@gasche的答案;使用累加器将使这变得更快,并避免列表的附加,每个列表的长度都是O(n)。嗯?这将是一个前序遍历,而不是后序遍历。作为参考,我使用的定义来自。此外,你的改变也无助于让你从一片叶子开始;这就是定义的函数的性质。你可以试着进一步限制它,不允许你从一片叶子开始,但这将是不必要的丑陋。