Delete an element from a binary search tree in F#

半世苍凉 提交于 2019-12-02 04:19:02

I'm not quite sure I understand the logic that your remove function is trying to implement. The usual way to do this is to write a recursive function that:

  • if x is smaller than the current, remove x from the left sub-tree recursively
  • if x is larger than the current, remove x from the rightsub-tree recursively
  • if x is equal to the current, drop the current node and merge the two trees

The way to encode this in F# is to write a recursive function using pattern matching - quite similar to the functions you wrote:

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 The following is not actually going to work!] This is almost complete, but you need to add the merge function. The logic for the merge function is the following:

  • If both trees are empty, return empty tree
  • If left is Bin(n, llst, lrst) and the right is rst then return a tree that contains n with llst on the left and (recursively) merged lrst and rst on the right (because elements in both of them are larger than n).
  • Similarly if right is Bin and left is anything else.

This is not going to produce a balanced binary tree, but it is a good start.

EDIT: I think that perhaps an easiest option is to write two functions - one to remove the largest and one to remove the smallest element of the tree (then when merging, you can just call one of these two). This might be easier than writing a fully general remove function.

The following removes the largest element and returns it, together with a new tree (without the largest element):

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)

I have followed the steps Tomas decribes in his post and I came up with this solution:

// 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

I tried this in the 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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!