根据Pearls of Functional Algorithm Design,无环功能是
想象一下用于生成某种组合模式的程序, 模式,例如列表的子序列或排列。
假设每个模式都是从它的前身获得的 过渡。对于子序列,转换 i 可能意味着 insert 或 删除 i 位置的元素。对于排列,转换 i 可能意味着“将位置 i 中的项目与位置 i - 1 中的项目交换。
生成所有模式的算法称为无循环 第一次转换以线性时间生成,以恒定时间的每次后续转换生成。请注意,它是过渡 恒定时间产生,而不是模式;写出一个模式是 通常不可能在不变的时间内。
例如,我们可以使用这样的二叉搜索树pre-order
遍历:
type 'a bst = Empty | Node of 'a bst * 'a * 'a bst
let rec preorder = function
| Empty -> []
| Node (l, x, r) -> x::preorder l @ preorder r
为了使pre-order
遍历无循环,我们需要准备第一个过渡:
let prepare t = [t]
然后我们定义step_f
,它是后续转换的函数:
let step_f = function
| [] -> None
| t::tl ->
match t with
| Empty -> failwith "wrong"
| Node (Empty, x, Empty) -> Some (x, tl)
| Node (Empty, x, c) | Node (c, x, Empty) -> Some (x, c::tl)
| Node (l, x, r) -> Some (x, l::r::tl)
基本上,step_f
直接取出一个元素并准备下一步可以用于下一步。
我们可以有一个标准的unfold
函数来连接整个过程
let rec unfold a =
match step_f a with
| None -> []
| Some (b, a') -> b::unfold a'
let _ = unfold (prepare bst)
这种无循环的东西当然可以用来构造惰性函数等。
我的问题是如何为bst顺序遍历设计无循环函数?
请注意,准备过程最多花费O(n)和步骤处理成本O(1)。
答案 0 :(得分:2)
我们可以在O(n)时间内轻松生成有序遍历,因此一种方法是:
生成有序遍历并将其存储在列表中
循环浏览列表,输出每个元素
这需要O(n)到达第一个,然后是每个O(1)。
O(n)有序遍历可以用这样的方法完成(伪代码):(来自Wikipedia)
inorder(node)
if node == null
return
inorder(node.left)
store(node)
inorder(node.right)
我真的不知道OCaml,但我希望这个基本想法仍然存在。