简体   繁体   English

从二叉搜索树中删除节点,haskell

[英]delete node from binary search tree, haskell

I'm making a Haskell function to delete a node from a Binary Search Tree. 我正在使用Haskell函数从二进制搜索树中删除节点。 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 没有孩子 - 删除,1个孩子 - 用孩子替换,2个孩子 - 在右子树中找到min并用值替换节点,然后,递归地从右子树中删除最小值

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. 无法弄清楚为什么treeBuilder也无法正常工作。 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 . 因此,您的deleteNode函数将不是String -> BST类型,它将是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. String是要删除的标签,第一个BST是输入树,第二个BST是输出树。

As @Ingo mentioned, you can implement deletion recursively by implementing the function: 正如@Ingo所提到的,您可以通过实现该函数来递归地实现删除:

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 ! 当然,如果你想在haskell中使用一个高效的,开箱即用的,已经实现的平衡二进制搜索树 - 只需导入Data.Map

Here is a deletion function implemented in Haskell using Mutual Recursion 这是使用Mutual Recursion在Haskell中实现的删除函数

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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