在OCaml中构建二进制搜索树的正确方法

时间:2013-01-22 14:24:48

标签: functional-programming ocaml binary-search-tree

好的,我在OCaml中写了binary search tree

type 'a bstree = 
    |Node of 'a * 'a bstree * 'a bstree
    |Leaf


let rec insert x = function
    |Leaf -> Node (x, Leaf, Leaf)
    |Node (y, left, right) as node -> 
        if x < y then
            Node (y, insert x left, right)
        else if x > y then
            Node (y, left, insert x right)
        else
            node

上述代码在The right way to use a data structure in OCaml

中被认为是好的

然而,我发现了一个问题。此insert仅在一次性从列表中构建bst时起作用,例如

let rec set_of_list = function
     [] > empty
   | x :: l > insert x (set_of_list l);;

因此,如果我们从列表中连续构建bst,没问题,我们可以获得一个包含列表中所有节点的完整bst。

但是,如果我之前已经构建了一个bst,现在我希望插入一个节点,那么生成的bst将不会有来自上一个树的完整节点我是对的吗?

然后我应该如何在OCaml中编写一个bst,以便我们创建一个包含前一个树中所有节点的新bst,以保持前一个树不可变?如果每次我需要从旧bst复制所有节点,这会影响性能吗?


修改

首先,让我们说一个bst是用一个节点t1 = (10, Leaf, Leaf)创建的。

然后我let t2 = insert 5 t1,然后我得到t2 = (10, (5, Leaf, Leaf), Leaf),对吗?在t2中,让我们给出一个变量c1 to the child node (5, Leaf, Leaf)

然后我let t5 = insert 12 t2,然后我得到t3 = (10, (5, Leaf, Leaf), (15, Leaf, Leaf))。让我们给出一个变量c2 to the child node (5, Leaf, Leaf)

所以我的问题是c1 == c2? t2和t3中的两个(5, Leaf, Leaf) s是否完全相同?

2 个答案:

答案 0 :(得分:4)

我会尝试回答你问题的分享部分。简短的回答是肯定的,两棵树的两个部分是相同的。不可变数据运行良好的原因是对可能的共享没有限制。这就是FP运作良好的原因。

这是一个完成你所描述的会话:

# let t1 = Node (10, Leaf, Leaf);;
val t1 : int bstree = Node (10, Leaf, Leaf)
# let t2 = insert 5 t1;;
val t2 : int bstree = Node (10, Node (5, Leaf, Leaf), Leaf)
# let t3 = insert 12 t2;;
val t3 : int bstree = Node (10, Node (5, Leaf, Leaf), Node (12, Leaf, Leaf))
# let Node (_, c1, _) = t2;;
val c1 : int bstree = Node (5, Leaf, Leaf)
# let Node (_, c2, _) = t3;;
val c2 : int bstree = Node (5, Leaf, Leaf)
# c1 == c2;;
- : bool = true

答案很长,不能保证这两个部分是相同的。如果编译器和/或运行时可以看到复制子树的原因,那么它也可以自由地执行。有些情况(如在分布式处理中),这将是一个更好的选择。关于FP的好处还在于共享没有限制,这意味着在这种情况下既不需要也不禁止共享。

答案 1 :(得分:2)

查看已链接问题的已接受答案。 具体这一行在这里:

  

让tree_of_list l = List.fold_right insert l Leaf

找出正在发生的事情的链条。列表1,2,3。

首先,我们没有树和插入1 Leaf的结果。

拨打此T1

接下来是插入2 T1

生成的树

称之为T2

然后插入3 T2生成的树

这是Tree_of_list返回的结果。

如果我们调用结果T3然后在代码调用插入4 T3中的其他地方,则从插入返回的结果与使用列表1,2,3,4调用Tree_of_list的结果没有区别。