【问题标题】:Delete an element from a binary search tree in F#从 F# 中的二叉搜索树中删除一个元素
【发布时间】:2016-01-30 10:37:02
【问题描述】:

我正在尝试编写一种从 BST 中删除元素的方法。到目前为止,这就是我所拥有的。我不确定我是否走在正确的轨道上,或者是否有更好的方法可以通过使用模式匹配来匹配不同的删除案例,即:没有孩子、1 个孩子、2 个孩子。

type 'a bst = NL | BinTree of 'a * 'a bst * 'a bst;;

let rec smallest = function
    | NL -> failwith "tree is empty"
    | BinTree(m, lst, rst) -> if lst = NL then BinTree(m, lst, rst)
                              else smallest lst;;

let rec smallest2 = function
    | NL -> failwith "tree is empty"
    | BinTree(m, lst, rst) -> if lst = NL then m
                              else smallest2 lst;;

let rec rem2 = function
    | NL -> NL
    | BinTree(m, NL, NL) -> NL
    | BinTree(m, NL, rst) -> rst
    | BinTree(m, lst, NL) -> lst
    | BinTree(m, lst, rst) -> BinTree(smallest2 rst, lst, rst);;


let rec rem x = function
    |NL -> failwith "Node doesn't exit"
    |BinTree(m, lst, rst) -> if m = x then rem2 (BinTree(m, lst, rst)) 
                             elif m < x then BinTree(m, lst, rem x rst) 
                             else BinTree(m, rem x lst, rst);;

没有子节点和单子节点的情况完美运行,但是当要删除的节点有2个子节点时,我不知道如何实现这种情况。我想用它的右子树上的最小项替换该节点的值,然后删除其右子树上的最小项。

【问题讨论】:

  • 你有什么问题?

标签: types f# binary-search-tree


【解决方案1】:

我不太确定我是否理解您的 remove 函数试图实现的逻辑。通常的方法是编写一个递归函数:

  • 如果x小于当前值,递归地从左子树中删除x
  • 如果x大于当前值,递归地从右子树中删除x
  • 如果x等于当前,删除当前节点,合并两棵树

在 F# 中对此进行编码的方法是使用模式匹配编写递归函数 - 与您编写的函数非常相似:

let rec remove x = function
  | NL -> NL
  | BinTree(m, lst, rst) when x = m -> merge lst rst
  | BinTree(m, lst, rst) when x < m -> BinTree(m, remove x lst, rst)
  | BinTree(m, lst, rst) (* x > m *) -> BinTree(m, lst, remove x rst)

[EDIT 下面的内容实际上是行不通的!] 这几乎完成了,但是您需要添加merge 函数。合并函数的逻辑如下:

  • 如果两棵树都是空的,则返回空树
  • 如果左边是Bin(n, llst, lrst),右边是rst,则返回一个包含n的树,左边是llst,并且(递归地)合并右边的lrstrst(因为元素它们都大于n)。
  • 同样,如果右边是 Bin 而左边是其他任何东西。

这不会产生一个平衡二叉树,但它是一个好的开始。

编辑:我认为也许最简单的选择是编写两个函数 - 一个删除树中最大的元素,一个删除树的最小元素(然后在合并时,您可以调用一个这两个)。这可能比编写一个完全通用的删除函数更容易。

以下删除最大元素并将其与新树(没有最大元素)一起返回:

let rec remLargest = function
  | NL -> failwith "Tree was empty!"
  | BinTree(m, l, NL) -> m, l
  | BinTree(m, l, r) -> 
      let res, newR = remLargest r
      res, BinTree(m, l, newR)

【讨论】:

  • 非常感谢您,这对我帮助很大!但是,合并没有按预期工作,即:当要删除的节点有 2 个子节点时,它会被删除,但树不会保持其 BST 排序。我尝试了另一种方法,将要删除的节点传递给 rem2 函数,然后处理个别情况,即:1 个孩子,2 个孩子,没有孩子。请查看我的编辑
【解决方案2】:

我已按照 Tomas 在他的帖子中描述的步骤进行操作,并提出了以下解决方案:

// BST - binary search tree
type BST<'a when 'a: comparison> = | Leaf
                                   | Node of BST<'a> * 'a * BST<'a>

let rec rmMaxBST = function
    | Leaf              -> failwith "Tree was empty"
    | Node(tL, x, Leaf) -> x, tL
    | Node(tL, x, tR  ) -> let m, newTR = rmMaxBST tR
                           m, Node(tL, x, newTR)

let rec rmMinBST = function
    | Leaf              -> failwith "Tree was empty"
    | Node(Leaf, x, tR) -> x, tR
    | Node(tL,   x, tR) -> let m, newTL = rmMinBST tL
                           m, Node(newTL, x, tR)

let mergeBST t1 t2 =
    match t1, t2 with
    | (Leaf, Leaf)      -> Leaf
    | (t1,   Leaf)      -> let x, t = rmMaxBST t1
                           Node(t, x, Leaf)               
    | (t1,   t2  )      -> let x, t = rmMinBST t2
                           Node(t1, x, t)              

let rec delBST x = function
    | Leaf                       -> Leaf
    | Node(tL, a, tR) when x < a -> Node(delBST x tL, a,          tR)
    | Node(tL, a, tR) when a < x -> Node(         tL, a, delBST x tR)
    | Node(tL, _, tR)            -> mergeBST tL tR

我在 REPL 中试过这个:

> delBST 3 Leaf;;

val it : BST<int> = Leaf

> delBST 3 (Node(Leaf, 4, Leaf));;

val it : BST<int> = Node (Leaf,4,Leaf)

> delBST 3 (Node(Leaf, 3, Leaf));;

val it : BST<int> = Leaf

> delBST 3 (Node(Node(Leaf, 1, Leaf), 3, Node(Leaf, 5,Leaf)));;

val it : BST<int> = Node (Node (Leaf,1,Leaf),5,Leaf)

> delBST 1 (Node(Node(Leaf, 1, Leaf), 3, Node(Leaf, 5,Leaf)));;

val it : BST<int> = Node (Leaf,3,Node (Leaf,5,Leaf))

> delBST 5 (Node(Node(Leaf, 1, Leaf), 3, Node(Leaf, 5,Leaf)));;

val it : BST<int> = Node (Node (Leaf,1,Leaf),3,Leaf)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多