简体   繁体   中英

delete node from binary search tree, haskell

I'm making a Haskell function to delete a node from a Binary Search Tree. I know the rules regarding the action needed to be taken depending on the number children the targeted parent has.

no children - delete, 1 child - replace with the child, 2 children - find the min in the right sub tree and replace the node with the value, - then, recursively delete the minimum value from the right sub-tree

data BST = MakeNode BST String BST
              |  Empty

deleteNode :: String -> BST



treeBuilder :: [String] -> BST
treeBuilder = foldr add Empty

add :: String -> BST -> BST
add new Empty = (MakeNode Empty new Empty)
add string tree@(MakeNode left value right)
    | string > value = MakeNode left value (add string right)
    | string < value = MakeNode (add string left) value right
    | otherwise = tree

can't figure out why treeBuilder isn't working correctly either. It just prints Strings Diagonally down to the right.

In these situations, it's best not to think about deleting a node from the tree; it's better to think of how to transform the tree you have into one without the node you want gone.

Let's do some case analysis:

If the tree is empty, then the result is empty, regardless of the key:

delete _ Empty = Empty

If the tree is non-empty, we have to see if the key matches the node. If it does not match, then we need to transform either the left or right subtree based upon whether the key is greater-than or less-than the node:

delete key (MakeNode l key' r) | key < key' = MakeNode (delete key l) key' r
delete key (MakeNode l key' r) | key > key' = MakeNode l key' (delete key r)

If it does match (which it must, since all of the no-match cases have been dealt with), then we have to figure out how to create a new tree without the root node. From your description, if the node has no children, just delete it:

delete _ (MakeNode Empty _ Empty) = Empty

If the node has one child, use that:

delete _ (MakeNode l _ Empty) = l
delete _ (MakeNode Empty _ r) = r

Otherwise, find and delete the minimum key in the right subtree, and use it as the new root's key:

delete _ (MakeNode l _ r) = MakeNode l key r' -- make a new root with min key and new r
  where key = minKey r    -- find the minimum key in the right subtree
        r' = delete key r -- new right subtree with min key removed

        -- a helper function to find the minimum key in a tree
        -- !! does not work on Empty tree !!
        minKey (MakeNode Empty key _) = key
        minKey (MakeNode l _ _) = minKey l

You can't! Everything is immutable!

What you can do is make a new tree that's exactly the same as the old one, except with one node removed. (Don't worry, your compiler won't need to duplicate much memory. Remember, everything is immutable. That means that the implementation can safely re-use the common parts!)

As such, your deleteNode function won't be of type String -> BST , it will be of type String -> BST -> BST . The String is the label you want removed, the first BST is the input tree, the second BST is the output tree.

As @Ingo mentioned, you can implement deletion recursively by implementing the function:

deleteNode :: String -> BST -> BST
deleteNode _ Empty = ...                          -- Handle the empty case
deleteNode x (BST left a right) | x == a    = ... -- Delete the node
                                | x < a     = ... -- Recurse on the lesser node
                                | otherwise = ... -- Recurse on the greater node

If you want to do some general munging beyond deletion (insertion, changes, etc.) in a traversable data structure (trees, lists, etc) I suggest you read up on zippers . They'll help you immensely.

Once you have a zipper for a binary tree, you can use zipper functions to delete nodes in the tree. If you'd like help implementing a zipper for your binary search tree data structure, let me know and I'll expand this. Right now it's probably overkill.

Be warned, a zipper won't re-balance your binary search tree for you. If you want to remove a node from your binary search tree and keep it balanced, that's a whole new can of worms.

There are a number of common balancing algorithms you could use, depending upon your taste. I suggest getting it working in an unbalanced fashion first, and then asking separate questions if you have trouble balancing it.

And, of course, if you want an efficient, out-of-the-box, already-implemented, balancing binary search tree in haskell -- just import Data.Map !

Here is a deletion function implemented in Haskell using Mutual Recursion

The type of the tree is:

type Key = Int
data BST = Nil | Node Key BST BST deriving (Show, Eq)

and here is the delete function:

delete :: Key -> BST -> BST
delete k Nil = Nil
delete k x@(Node a l r)
  | (k < a) = Node a (delete k l) r
  | (k > a) = Node a l (delete k r)
  | (k == a) = delete' k x

delete' :: Key -> BST -> BST
delete' k (Node a l r)
  | (l == Nil)  = r
  | (r == Nil)  = l
  | otherwise    = let (k,t) = maxAndDelete l
                    in Node k t r

-- This function finds the maximum and then deletes the node as well
maxAndDelete :: BST -> (Key,BST)
maxAndDelete t = let m = treeMaximum t
                  in (m,delete m t)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM