如果有人对这种改进感兴趣,可以通过线程化一个额外的累加器参数,在性能方面比 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
beforeacc
给出了列表中最终元素顺序的直觉: 的元素t
将在中已经存在的元素之前acc
。这使得N
案例可以很自然地阅读:很容易看出结果将首先具有 的元素a
,然后是b
,然后是None
,然后是acc
。
最后,您当然可以定义store
为store'
:
let store t = store' t []
习惯上将第一个定义包装在第二个定义中(如果您不想向用户公开这个“低级”功能),并给它与外部定义相同的名称(这不冲突因为它不是递归的,所以不进入内部范围):
let store t =
let rec store t acc = match t with
| L x -> Some x :: acc
| N (a, b) ->
store a (store b (None :: acc))
in store t []
当然,这个定义是否比 Len 的定义“更好”取决于你的评价标准是什么。Len 的解决方案更短,更易于阅读,并且更紧密地映射了原始问题。
(您可以通过使用惰性枚举而不是严格列表来获得两全其美,但那是另一回事了。)