以特殊方式穿越树

时间:2015-11-24 21:54:58

标签: algorithm ocaml

我们有一个二叉树

type 'a tree = Node of 'a * 'a tree * 'a tree | Null ;;

我们希望以特定的顺序返回包含所有顶点的'a list,即列表中两个相邻顶点之间的距离不能超过3.每个顶点只能出现一次。

实施例。对于树

      1
     / \
    2   6
   /
  3
 / \
4   5

一个可能的答案是[1; 3; 4; 5; 2; 6]

暂时我有以下代码:

let walk t =
    let rec pom_walk t acc end_root = (* it's symmetric, so it could be start_root and the result would be correct too *)
        match t with
        | Null -> acc
        | Node (nr, l, r) ->
            if end_root then
                nr::(pom_walk r (pom_walk l acc false) false)
            else
                (pom_walk r (pom_walk l acc true) true) @ [nr]
     in
        pom_walk t [] true 

但由于@运算符的使用,此代码具有方形复杂性,该运算符本身就是线性的。

如何在线性时间内解决这个问题?

2 个答案:

答案 0 :(得分:1)

因为您在前面列表后面推送元素,所以能够轻松执行这两项操作会很不错。正如@ david-eisenstat建议的那样,您可以使用difference lists

我在这里提出了一个不同的解决方案。我们将通过两个列表来表示我们的列表:初始段和(反向)结束段。

type 'a init_last = 'a list * 'a list

我们可以通过提供一个函数to_list将这样的'a init_last转换为它代表的'a list来使这种直觉更正式:

let to_list (xs : 'a init_last) : 'a list =
  let (init, last) = xs in init @ rev last

现在可以很容易地定义辅助函数来定义空'a init_last的外观,并在常量时间内将项目放在我们的'a init_last所代表的列表的顶部/末尾:

let empty : 'a init_last = ([], [])

let push_top (a : 'a) (xs : 'a init_last) : 'a init_last =
  let (init, last) = xs in (a :: init, last)

let push_end (xs : 'a init_last) (a : 'a) : 'a init_last =
  let (init, last) = xs in (init, a :: last)

然后我们可以在walk的定义中使用这些组合子,并通过使用'a listpom_walk的结果进行后处理来返回更传统的to_list

let walk t =
    let rec pom_walk t acc end_root =
        match t with
        | Null -> acc
        | Node (nr, l, r) ->
            if end_root then
                push_top nr (pom_walk r (pom_walk l acc false) false)
            else
                push_end (pom_walk r (pom_walk l acc true) true) nr
     in
        to_list (pom_walk t empty true)

答案 1 :(得分:0)

@gallais展示了一个很好的解决方案,我想分享我想出的那个。请仔细检查,直到没有任何东西;)

let walk t =
    let rec pom_walk t cont end_root =
        match t with
        | Null -> cont
        | Node (nr, l, r) ->
            let resL = pom_walk l cont (not end_root) in
            let resR = pom_walk r resL (not end_root) in
                if end_root then
                    function res -> nr::(resR res)
                else
                    function res -> resR (nr::res)
     in
        pom_walk t (fun x -> x) true []