好的,我在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是否完全相同?
答案 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的结果没有区别。