2

好的,我已经binary search tree在 OCaml 中编写了一个。

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

我猜上面的代码没有问题。

使用时,我写

let root = insert 4 Leaf

let root = insert 5 root

...

这是通往use/insert树的正确方法吗?

我的意思是,我想我不应该声明根并且每次我再次更改变量根的值,对吧?

如果是这样,我怎样才能始终保持根并可以随时将值插入树中?

4

1 回答 1

8

这看起来像是插入树的良好功能代码。它不会在插入过程中改变树,而是创建一个包含该值的新树。不可变数据的基本思想是你不“保留”东西。您计算值并将它们传递给新函数。例如,这是一个从列表创建树的函数:

let tree_of_list l = List.fold_right insert l Leaf

它通过将当前树传递给对insert.

以这种方式思考是值得学习的,因为 FP 的许多好处都来自于不可变数据的使用。然而,OCaml 是一种混合范式语言。如果您愿意,您可以使用引用(或可变记录字段)在更改值时“保留”一棵树,就像在普通命令式编程中一样。

编辑:

您可能会认为以下会话显示了对变量 x 的修改:

# let x = 2;;
val x : int = 2
# let x = 3;;
val x : int = 3
# 

然而,看待这一点的方式是,这是两个不同的值,碰巧都被命名为 x。因为名称相同,所以 x 的旧值被隐藏。但是,如果您有另一种访问旧值的方法,它仍然会存在。也许以下将显示事情是如何工作的:

# let x = 2;;
val x : int = 2
# let f () = x + 5;;
val f : unit -> int = <fun>
# f ();;
- : int = 7
# let x = 8;;
val x : int = 8
# f ();;
- : int = 7
# 

创建一个名为x8 的新事物不会影响f它的作用。它仍然使用x定义时存在的旧版本。

编辑2:

从树中删除一个不可变的值类似于添加一个值。即,您实际上并没有修改现有的树。您创建了一个没有您不想要的值的新树。正如插入不会复制整个树(它会重复使用前一棵树的大部分),所以删除也不会复制整个树。树中未更改的任何部分都可以在新树中重新使用。

编辑 3

这是一些从树中删除值的代码。它使用一个辅助函数来连接两棵已知不相交的树(此外,a 中的所有值都小于 b 中的所有值):

let rec adjoin a b =
    match a, b with
    | Leaf, _ -> b
    | _, Leaf -> a
    | Node (v, al, ar), _ -> Node (v, al, adjoin ar b)

let rec delete x = function
    | Leaf -> Leaf
    | Node (v, l, r) ->
        if x = v then adjoin l r
        else if x < v then Node (v, delete x l, r)
        else Node (v, l, delete x r)

(希望我没有破坏你的作业!)

于 2013-01-21T14:44:07.043 回答