二阶搜索树有序遍历的无循环函数算法

时间:2014-04-16 14:02:18

标签: algorithm ocaml lazy-evaluation

根据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)。

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,但我希望这个基本想法仍然存在。