I have the defined Type: data Tree = Node Tree Tree | Leaf Int | NIL. I want create a method delete :: Tree -> Int -> Tree which removes all Leaf's with the specific Int given in the second parameter.
If your tree doesn't have any particular structure, you can do
delete NIL _ = NIL
delete (Leaf i) int | i == int = NIL
| otherwise = Leaf i
delete (Node left right) int = Node (delete left int) (delete right int)
Why?
delete NIL _ = NIL because we have to deal with all cases, even the empty trees at the ends. The _ stands for any value that we don't care about.
delete (Leaf i) int | i == int = NIL
| otherwise = Leaf i
because we need to first check | i== int to see whether we want to delete the node. If we do, we replace it with the empty three, NIL. Otherwise, we leave it alone.
delete (Node left right) int = Node (delete left int) (delete right int) because if we're at a node, we need to delete the int from both left and right subtrees.
Aren't you going to end up with a whole load of NILs?
Yes, I suppose that could happen. You could clear up with
prune (Node NIL NIL ) = NIL
prune (Node (Leaf i) NIL ) = Leaf i
prune (Node NIL (Leaf i)) = Leaf i
prune (Node (Leaf i) (Leaf j)) = Node (Leaf i) (Leaf j)
prune (Node left right ) = prune (Node (prune left) (prune right))
prune t = t
The first three lines get rid of a NIL on the left, right or both, and the fourth leaves two leaves alone.
The fifth line only gets called when one of the left or right subtrees of this node is itself a node. Why prune three times? Maybe when you prune left and prune right one or more of them ends up NIL.
The prune t = t deals with both NIL and Leaf i in one neat pattern match.
I would suggest some improvements to AndrewC's answer. While his solution is absolutely correct, it has some potential performance issue.
The issue is: both delete and prune functions create a new copy of the whole tree on every call. That happens regardless of whether an element was actually deleted.
The worst case scenario is deleting a non-existing element.
Let's say we have a really big tree that holds 1M of integers. Since integers are stored in leaves only, the whole tree contains at least 2M-1 of nodes. (Or even more if the tree was not pruned yet thus contains NIL nodes).
When we try to delete a non-existing element from such a huge tree, our delete function will do absolutely nothing but duplicating all 2M of nodes. (And prune will duplicate them again!)
Deleting an existing element is just a tiny bit better. At this case, delete removes one leaf, updates it's parent and duplicates the rest of the tree. prune will probably remove a few more nodes but will duplicate the rest.
Why does that happen?
There are two places where duplication happens.
This line creates a new tree that is completely identical to the argument:
delete (Leaf i) int | ...
| otherwise = Leaf i
Also, this line creates a new tree even if the element is not present in both left and right branches:
delete (Node left right) int = Node (delete left int) (delete right int)
Is it possible to avoid unnecessary duplication?
Yes, of course. We just need to return the argument if we do not modify it.
Here is my version:
delete t i = fst $ delete' t i
where delete' NIL _ = (NIL, True)
delete' t#(Leaf i) int | i == int = (NIL, False)
| otherwise = (t, True)
delete' t#(Node left right) int =
let (left', unchangedLeft) = delete' left int
(right', unchangedRight) = delete' right int
in
if unchangedLeft && unchangedRight
then (t, True)
else (Node left' right', False)
As you can see, I use a helper function delete' that returns a pair of (Tree, Bool) where second element is True if the tree was not changed, and False otherwise.
This function builds a new tree that shares most of the nodes with the original one. It only changes nodes on the path from root to the deleted element.
What about prune ?
The version above does not delete NIL elements. As AndrewC noted, after performing multiple deletes we may have a tree with a lot of NILs. To address this issue, we can either modify prune in the similar way, or we can merely integrate it into the delete:
delete t i = fst $ delete'' t i
where delete'' NIL _ = (NIL, True)
delete'' t#(Leaf i) int | i == int = (NIL, False)
| otherwise = (t, True)
delete'' t#(Node left right) int =
let (left', unchangedLeft) = delete'' left int
(right', unchangedRight) = delete'' right int
in
if unchangedLeft && unchangedRight
then (t, True)
else (newNode left' right', False)
newNode NIL r = r
newNode l NIL = l
newNode l r = Node l r
Related
So I have a tree defined as follows:
data Tree = Node Tree Int Tree | Leaf Int
The Int for a Node in this case is the value at that Node. I am trying to check that a tree is balanced, and that the tree is increasing as it's traversed left to right.
To do so I have a recursive function that takes a (Node left x right) and checks that the difference in height of left and right (the nodes below it) is no more than one. I then call balanced again for left and right.
Is it possible to access the Int value of left and right?
Yes, you can write a function that returns the integer at the top node:
getInt (Node _ i _) = i
getInt (Leaf i) = i
E.g.
Prelude> getInt $ Leaf 42
42
Prelude> getInt $ Node (Leaf 42) 123 (Leaf 1337)
123
Of course you can, instead of put variables like left and right, use the constructors again:
Edit, I forget the case of Leaf, it has also an int:
data Tree = Node Tree Int Tree | Leaf Int
exampleSumNodes (Node left x right) = (treeToInt left) + x + (treeToInt right)
treeToInt (Node _ n _) = n
treeToInt (Leaf n ) = n
I'm trying to get a function that counts all paths from the root to a leaf that has an even number of nodes ( counting the root and the leaf)
My tree looks like this:
data Tree = Leaf Int | Node Int Tree Tree
all i got so far is a function that counts ALL nodes in a tree, which is easy enough:
countNodes (Leaf _) = 1
countNodes (Node _ x y) = 1+ countNodes x + countNodes y
Now i saw a bunch of questions that deal with trees but i felt like no answer helped me much, so I'm just gonna ask myself. How do i make a part of a function stop when a leaf is reached? I know this has to do with my problem to think with recursions.
What I tried to do was to to make list of all paths from the root, but i always end up with a function that gets all elements in the tree and puts them together somehow.
I'm missing something simple, please help. (or link me an answer that does exactly what i want)
I think the easiest way would be to make a data type that can describe a path through a tree:
data Path = L Path | R Path | End deriving (Eq, Show)
This type is basically a list but with two prepend constructors to tell you either go Left or go Right. This conveniently lets you look up items by path, or you can write a function that gives you a list of all paths in the tree.
-- Note that this can fail: lookupNode (Leaf 1) (L End) == Nothing
lookupNode :: Tree -> Path -> Maybe Tree
allPaths :: Tree -> [Path]
If you can write the allPaths function, then you can write the function you want on top of it. To start, just begin by listing the base cases:
allPaths (Leaf _) = [End]
allPaths (Node _ left right) = _
To fill in the hole _, think about what it means to list all the paths starting at a Node and recursing down left. You would need to have a L at the beginning of all of those paths, so you can put the following in there
allPaths (Node _ left right) = (map L $ allPaths left)
Similarly, you would need to handle the right tree:
allPaths (Node _ left right) =
(map L $ allPaths left) ++
(map R $ allPaths right)
So now:
> let tree =
Node 1
(Node 2 -- L _
(Leaf 3) -- L (L End)
(Node 4 -- L (R _)
(Leaf 5) -- L (R (L End))
(Leaf 6) -- L (R (R End))
)
)
(Leaf 7) -- R End
> allPaths tree
[L (L End),L (R (L End)), L (R (R End)),R End]
Now, to find the Leafs with an even number of nodes above them, first write a function that calculates a path length:
pathLength :: Path -> Int
pathLength End = 0
pathLength (L rest) = 1 + pathlength rest
pathLength (R rest) = 1 + pathLength rest
evenNodeCountPaths :: Tree -> [Path]
evenNodeCountPaths tree = filter (even . pathLength) $ allPaths tree
Note: It is possible to do this with
data Dir = L | R | End
type Path = [Dir]
But that can lead to invalid paths like [End, End, L, R, End], which just doesn't make any sense. I chose to go for the list-like data Path for this reason. You have to write your own pathLength function, but this formulation makes it impossible to have invalid paths.
Probably it's easier to compute both the number of even and the number of odd paths.
evenAndOdd (Leaf _) = (0, 1)
evenAndOdd (Node _ l r) = let
(el, ol) = evenAndOdd l
(er, or) = evenAndOdd r
in (ol+or, el+er)
If you really must, you can then define a function in terms of this to count just the even paths.
evenOnly = fst . evenAndOdd
Assume I have a binary tree:
data Bst a = Empty | Node (Bst a) a (Bst a)
I have to write a function that searches for a value and returns the number of its children. If there is no node with this value, it returns -1. I was trying to write both BFS and DFS, and I failed with both.
Pattern matching is your friend. Your Bst can either be Empty or a Node, so at the toplevel, your search function will be
search Empty = ...
search (Node left x right) = ...
Can an Empty tree possibly contain the target value? With a Node the target value, if present, will be either the node value (x above), in the left subtree, in the right subtree—or perhaps some combination of these.
By “return[ing] the number of its children,” I assume you mean the total number of descendants of the Bst rooted at a Node whose value is the target, which is an interesting combination of problems. You will want another function, say numChildren, whose definition uses pattern matching as above. Considerations:
How many descendants does an Empty tree have?
In the Node case, x doesn’t count because you want descendants. If only you had a function to count the number of children in the left and right subtrees …
Here is a way to do this. Breath-first search can actually be a bit tricky to implement and this solution (findBFS) has aweful complexity (appending to the list is O(n)) but you'll get the gist.
First I have decided to split out the finding functions to return the tree where the node element matches. That simplifies splitting out the counting function. Also, it is easier to return the number of elements than the number of descendants and return -1 in case not found, so the numDesc functions rely on the numElements function.
data Tree a = Empty
| Node a (Tree a) (Tree a)
numElements :: Tree a -> Int
numElements Empty = 0
numElements (Node _ l r) = 1 + numElements l + numElements r
findDFS :: Eq a => a -> Tree a -> Tree a
findDFS _ Empty = Empty
findDFS x node#(Node y l r) | x == y = node
| otherwise = case findDFS x l of
node'#(Node _ _ _) -> node'
Empty -> findDFS x r
findBFS :: Eq a => a -> [Tree a] -> Tree a
findBFS x [] = Empty
findBFS x ((Empty):ts) = findBFS x ts
findBFS x (node#(Node y _ _):ts) | x == y = node
findBFS x ((Node _ l r):ts) = findBFS x (ts ++ [l,r])
numDescDFS :: Eq a => a -> Tree a -> Int
numDescDFS x t = numElements (findDFS x t) - 1
numDescBFS :: Eq a => a -> Tree a -> Int
numDescBFS x t = numElements (findBFS x [t]) - 1
When I compile the following code with GHC (using the -Wall flag):
module Main where
data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show)
insert :: (Ord a) => a -> Tree a -> Tree a
insert x EmptyTree = Node x EmptyTree EmptyTree
insert x (Node a left right)
| x == a = Node a left right
| x < a = Node a (insert x left) right
| x > a = Node a left (insert x right)
main :: IO()
main = do
let nums = [1..10]::[Int]
print . foldr insert EmptyTree $ nums
GHC complains that pattern matching in insert is non-exhaustive:
test.hs|6| 1:
|| Warning: Pattern match(es) are non-exhaustive
|| In an equation for `insert': Patterns not matched: _ (Node _ _ _)
Why is GHC issuing this warning? It is pretty obvious that the pattern GHC complains about is handled in insert x (Node a left right).
It's because the pattern matching is incomplete. There's no guarantee that one of x==a, x<a, or x>a holds. For instance, if the type is Double and x is NaN then none of them are True.
Riccardo is correct, GHC doesn't infer that your guards can't possibly all be false. So accept his answer please.
I'm going to digress and talk about coding style.
Your motivation for not using otherwise may have been that it looks unsightly:
insert :: (Ord a) => a -> Tree a -> Tree a
insert x EmptyTree = Node x EmptyTree EmptyTree
insert x (Node a left right)
| x == a = Node a left right
| x < a = Node a (insert x left) right
| otherwise = Node a left (insert x right)
Looking at this code, a human reader must confirm to themselves that the final guard accepts precisely those cases where x > a.
We could instead write it like this:
insert :: (Ord a) => a -> Tree a -> Tree a
insert x EmptyTree = Node x EmptyTree EmptyTree
insert x (Node a left right) = case x `compare` a of
EQ -> Node a left right
LT -> Node a (insert x left) right
GT -> Node a left (insert x right)
The Ordering type returned by compare has only the three values EQ, LT, and GT, so GHC can confirm that you've covered all possibilities, and a human reader can easily see that you've covered them correctly.
This is also more efficient code: we call compare once, instead of calling == and then probably calling < as well.
Now I'm going to digress some more and talk about laziness.
You've probably also written a function similar to this:
contains :: (Ord a) => a -> Tree a -> Bool
contains _ EmptyTree = False
contains x (Node a left right) = case x `compare` a of
EQ -> True
...
When x == a, you need to know that the tree uses the Node constructor, and that its first argument is equal to x. You don't need to know what either of the subtrees are.
But now look back at my definition of insert above. When the tree it's given is a Node, it always returns a Node whose first argument is always a. But it doesn't state that up front: instead it evaluates x `compare` a.
We can rewrite insert to perform the comparison as late as possible:
insert :: (Ord a) => a -> Tree a -> Tree a
insert x EmptyTree = Node x EmptyTree EmptyTree
insert x (Node a left right) = Node a newLeft newRight
where comparison = x `compare` a
newLeft = if comparison == LT then insert x left else left
newRight = if comparison == GT then insert x right else right
Now we return the Node a bit as soon as possible --- even if the comparison throws an error! --- and we still perform the comparison once at most.
GHC is not able to infer whether your three guards in the insert x (Node a left right) cover all possible cases, and consequently there will be no body to be associated with insert x (Node a left right). Try replacing the last condition x > a with otherwise (a synonim for True).
In this specific case however, it's true that the guards do not cover all cases, see augustss' example about double numbers.
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)