【问题标题】:Deletion in Binary Search Tree in OCamlOCaml 中二叉搜索树的删除
【发布时间】:2016-09-23 13:28:44
【问题描述】:

我正在 OCaml 中构造binary search tree 的操作。

type ('a, 'b) bst = 
  | Node of 'a * 'b * ('a, 'b) bst * ('a, 'b) bst
  | Leaf;;

let rec insert k v = function
  | Leaf -> Node (k, v, Leaf, Leaf)
  | Node (k', v', left, right) ->
    if k < k' then Node (k', v', insert k v left, right)
    else if k = k' then Node (k, v, left, right)
    else Node (k', v', left, insert k v right);;

let rec delete k = function
  | Leaf -> Leaf
  | Node (k', v, l, r) as p ->
    if k < k' then Node (k', v, (delete k l),r)
    else if k > k' then Node (k', v, l, (delete k r))
    else 
    match (l, r) with
      | (Leaf, Leaf) -> Leaf
      | (l, Leaf) -> l
      | (Leaf, r) -> r
      | (_, _) ->
        let Node (km, vm, _, _) = max l in
        Node (km, vm, delete km l, Leaf)

谁能告诉我我的deletion 代码是否足够好或有任何改进?

【问题讨论】:

    标签: functional-programming ocaml


    【解决方案1】:

    当我们插入树中的东西或删除树中不存在的东西时,这是一种改进。这些操作中的每一个都将复制到该特定节点的搜索路径。插入可能不是问题,因为您将要更新该键的值,但删除将是您可以进行改进的情况。这可以通过用异常包装函数以返回原始树来解决。

    以下是对不在树中的内容进行删除的样子。当您递归时,您创建一个新的Node,并在正确的子树中删除了键。在这种特殊情况下,delete 函数将递归到Leaf,然后返回Leaf,并且在堆栈的每一步备份中返回一个新构造的Node。这条新路径表示为下面的蓝色路径。由于没有将新路径展开到旧路径的结构,我们在结果树中重新创建搜索路径。

    let at = delete x bt
    

    要解决此问题,如前所述,将函数包装在异常中。

    let delete k t =
        let rec delete k = function
            | Leaf -> raise Not_found
            ...
        in
        try delete k t with Not_found -> t
    

    【讨论】:

    • 我认为在我的情况下,如果删除找不到键,那么将返回相同的树,不是吗?
    • 没有。我在上面正确地描述了删除。它在结构上是同一棵树,但在物理上不是。这些递归调用每次调用都会重新构造一个新的Node。您可以将其视为准备一个新节点,假设我们要删除左子树(或右子树)上的某些内容。当然,这个假设是不正确的,我们最终会得到一个Leaf,它返回一个Leaf,但是当没有任何内容被删除时,绝不会展开新路径到旧路径。
    • 这只是一种性能改进,只有在大树或树上的数据很大时才会发挥作用。但总的来说,我认为这是正确处理递归数据结构以及它们如何在高级别的内存中存储的一个很好的说明性示例。 Okasaki 在他的书“Purely Functional Data Structures”的练习 2.3 中提到了它。
    猜你喜欢
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-28
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多