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
Related
I have trees of the form:
data Tree a = Leaf | Node (Tree a) a (Tree a)
I created a function to look up the value of a node in a tree based on an in-order, left-to-right traversal.
getElem :: Tree a -> Int -> Maybe a
getElem Leaf _ = Nothing
getElem (Node l x r) n
| s == n = Just x
| n < s = getElem l n
| otherwise = getElem r (n - s - 1)
where
s = size l
I now want to write a method to be able to update a tree. It should be able to take in a tree, an index and a value and update the node at that index with the value. So far I have:
update :: Tree a -> Int -> a -> Tree a
update Leaf _ _ = Leaf
update (Node l x r) index c
| s == index = (Node l c r)
| index < s = update l index c
| otherwise = update r (index - s - 1) c
where
s = size l
This function is able to add but it obviously returns just the added node itself. I want to be able to return the entire tree post the 'update' with the new node or return the tree as is if the index is out of bounds.
Could anybody give me some idea how to proceed with this?
Edit 1:
Okay, I understand that I am basically discarding the remainder of my tree when recursing here. So:
update :: Tree a -> Int -> a -> Tree a
update Leaf _ _ = Leaf
update (Node l x r) index c
| s == index = (Node l c r)
| index < s = update (Node l2 x r) index c
| otherwise = update (Node l x r2) (index - s - 1) c
where
s = size l
l2 = l
r2 = r
Edit 2(Silly me!):
update :: Tree a -> Int -> a -> Tree a
update Leaf _ _ = Leaf
update (Node l x r) index c
| s == index = (Node l c r)
| index < s = (Node (upd l index c) x r)
| otherwise = (Node l x (upd r (index - s - 1) c))
where
s = size l
It took me a bit to wrap my head around it. Thank you for the comments!
Since in Haskell all data is immutable, you can not "update" a tree, you construct a new tree. That tree might however have references to subtrees of the old tree. You thus do not per se construct a completely new tree.
You managed to create an "updated" node, so now the only thing that is missing, is to use the "updated" subtree in a new tree. In that tree, you can use the "old" value together with the other subtree to construct a new one, like:
update :: Tree a -> Int -> a -> Tree a
update Leaf _ _ = Leaf
update (Node l x r) index c
| s == index = Node l c r
| index < s = Node (update l index c) x r
| otherwise = Node l x (update r (index - s - 1) c)
where s = size l
You might also need to change the Leaf case if you "count" a leaf as a node.
Trees with indices are not very common. It might also - in order to boost performance - be better to keep track of the number of items in the left subchild (or both), since then we can just pick the left or right subchild without counting the children. By keeping track of the number, for a complete tree, then updating the tree is an O(log n) operation, not an O(n) operation.
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.
Can someone tell me why this code isn't producing what I want.
data BST = MakeNode BST String BST
| 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
output
"John"
"Doug"
"Charlie"
"Alice"
listToBST :: [String] -> BST
listToBST = foldr add Empty
If we create and function which takes a BST and returns a list in sorted order, modelled after sort . nub, then your Tree is fine as quickcheck tells us. QuickCheck is very easy to use.
import Data.List
import Test.QuickCheck
data BST = MakeNode BST String BST
| Empty
deriving (Show)
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
test = ["alice", "blup", "test", "aa"]
manual_test = inorder (foldr add Empty test) == sort (nub test)
prop_inorder = property inorder_test
where inorder_test :: [String] -> Bool
inorder_test xs = inorder (foldr add Empty xs) == sort (nub xs)
-- return sorted nodes
inorder :: BST -> [String]
inorder (Empty) = []
inorder (MakeNode l x r) = inorder l ++ (x : inorder r)
Just load ghci and then run quickCheck prop_inorder.
Other useful functions are:
reverseOrder :: BST -> [String]
reverseOrder Empty = []
reverseOrder (MakeNode l x r) = reverseOrder r ++ (x : reverseOrder r)
asList :: BST -> [String]
asList Empty = []
asList (MakeNode l x r) = x : (asList l ++ asList r)
And also think about making your tree more general by parameterizing over a:
data BST a = Empty | MakeNode (BST a) a (BST a)
You can make it than an instance of Functor, Monad, Foldable and all kind of handy typeclasses.
I tried it and it seems ok to me. It could help if you gave an example of an input that it doesn't work for.
I think the problem may be that string comparison does not work the way you expect ("123" < "7" because "1" < "7"). If I'm right, you might want to use Ints instead of Strings or even better, the class Ord of all the types that can be ordered using (<).
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)
module Main where
import Data.List
import Data.Function
type Raw = (String, String)
icards = [("the", "le"),("savage", "violent"),("work", "travail"),
("wild", "sauvage"),("chance", "occasion"),("than a", "qu'un")]
data Entry = Entry {wrd, def :: String, len :: Int, phr :: Bool}
deriving Show
-- French-to-English, search-tree section
entries' :: [Entry]
entries' = map (\(x, y) -> Entry y x (length y) (' ' `elem` y)) icards
data Tree a = Empty | Tree a (Tree a) (Tree a)
tree :: Tree Entry
tree = build entries'
build :: [Entry] -> Tree Entry
build [] = Empty
build (e:es) = ins e (build es)
ins :: Entry -> Tree Entry -> Tree Entry
...
find :: Tree Entry -> Word -> String
...
translate' :: String -> String
translate' = unwords . (map (find tree)) . words
so i'm trying to design function ins and find but i am not sure where to start.any ideas?
I have no idea by which criteria the tree should be sorted, so I use just wrd. Then it would look like:
ins :: Entry -> Tree Entry -> Tree Entry
ins entry Empty = Tree entry Empty Empty
ins entry#(Entry w _ _ _) (Tree current#(Entry w1 _ _ _) left right)
| w == w1 = error "duplicate entry"
| w < w1 = Tree current (ins entry left) right
| otherwise = Tree current left (ins entry right)
How to get there?
As always when using recursion, you need a base case. Here it is very simple: If the tree is empty, just replace it by a node containing your data. There are no children for the new node, so we use Empty.
The case if you have a full node looks more difficult, but this is just due to pattern matching, the idea is very simple: If the entry is "smaller" you need to replace the left child with a version that contains the entry, if it is "bigger" you need to replace the right child.
If both node and entry have the same "size" you have three options: keep the old node, replace it by the new one (keeping the children) or throw an error (which seems the cleanest solution, so I did it here).
A simple generalization of Landei's answer:
ins :: Ord a => a -> Tree a -> Tree a
ins x Empty = Tree x Empty Empty
ins x (Tree x' l r) = case compare x x' of
EQ -> undefined
LT -> Tree x' (ins x l) r
GT -> Tree x' l (ins x r)
For this to work on Tree Entry, you will need to define an instance of Ord for Entry.