Trees
Binary Search Trees
Consider the following Binary Tree type
data Tree a = Leaf | Node (Tree a) a (Tree a)
Write the function
elemTree
that tests if an elementx
occurs in a binary search tree of typeTree a
.elemTree :: Ord a => a -> Tree a -> Bool = succOf q t == q elemTree q t -- or directly: elemTree :: Ord a => a -> Tree a -> Bool Leaf = False elemTree _ Node l x r) | q < x = elemTree q l elemTree q (| q == x = True | otherwise = elemTree q r
Write functions that return all values of type
a
in a tree of typeTree a
in depth-first (pre-order), depth-first (in-order), and breadth-first order.traverseTree :: ([a] -> a -> [a] -> [a]) -> Tree a -> [a] Leaf = [] traverseTree _ Node l x r) = traverseTree combine ( combine (traverseTree combine l) x (traverseTree combine r) preOrderTraversal :: Tree a -> [a] = traverseTree (\l x r -> x : (l ++ r)) preOrderTraversal inOrderTraversal :: Tree a -> [a] = traverseTree (\l x r -> l ++ (x : r)) inOrderTraversal
Write a function
showTree
that gives a nice representation as aString
for a given tree. Every leaf should be placed on a different line (separated by"\n"
). Leaves that are deeper in the tree should be further to the right than leaves higher in the tree.Write a function
mapTree
and a functionfoldTree
that work on aTree
, analoguous tomap
andfoldr
on lists. Also give the type of these functions.mapTree :: (a -> b) -> Tree a -> Tree b Leaf = Leaf mapTree _ Node l x r) = Node (mapTree f l) (f x) (mapTree f r) mapTree f ( foldTree :: (b -> a -> b -> b) -> b -> Tree a -> b Leaf = z foldTree _ z Node l x r) = f (foldTree f z l) x (foldTree f z r) foldTree f z (
Write a function
height
, that computes the amount of levels in aTree
. Give a definition using recursion, and a different definition usingfoldTree
.= foldTree (\l _ r -> 1 + l `max` r) 1 height
Suppose that a tree
t
has heightn
. What is the minimal and maximal amount of leaves thatt
could have?Write a function that computes all paths of type
[a]
from the root up to a leaf for a tree of typeTree a
.paths :: Tree a -> [[a]] Leaf = [[]] paths Node l x r) = map (x:) (paths l) ++ map (x:) (paths r) paths (
Write a function that computes a list of nodes that occur on one of the longest paths from the root up to a leaf. Try to keep the solution linear with respect to the size of the tree.
Write
mapTree
usingfoldTree
= foldTree (\l x r -> Node l (f x) r) Leaf mapTree f
Write a function
extractMin
that removes the smallest element from a binary search tree. Returns the smallest element and the remainder of the tree.extractMin :: Tree a -> Maybe (a, Tree a) Leaf = Nothing extractMin Node l k r) = case extractMin l of extractMin (Nothing -> Just (k, r) Just (m,l') -> Just (m, Node l' k r)
Write a function
delete
that deletes an element from the tree. You can assume the element appears at most once. Your new tree should remain a binary search tree.Hint: You may want to use the function
extractMin
you defined above.delete :: Ord a => a -> Tree a -> Tree a Leaf = Leaf delete _ Node l k r) = case x `compare` k of delete x (LT -> Node (delete x l) k r EQ -> case extractMin r of Nothing -> l Just (m,r') -> Node l m r' -- we replace k by its successor. GT -> Node l k (delete x r)
Trees with values in the Leaves
Define a binary tree type in which leaves store values of type
a
and internal nodes store values of typeb
data Tree a b = Leaf a | Node (Tree a b) b (Tree a b) deriving (Show,Eq)
Define a function
height
that given a Tree computes the height of theTree a b
. Leaves have height one.height :: Tree a b -> Int Leaf _) = 1 height (Node l _ r) = 1 + max (height l) (height r) height (
Define a function
annotate
, that given aTree b Int
labels every internal node with the minimum and maximum value appearing in the leaves in its subtree.e.g.
Node (Node (Leaf 3) "left" (Leaf 5)) "root" Leaf 1) ( -> Node (Node (Leaf 3) (3,5) (Leaf 5)) 1,5) (Leaf 1) (
annotate :: Tree b Int -> Tree (Int,Int) Int = case annotate' t of annotate t -> t' (t',_,_) -- | Computes the annotated tree, as well as the minimum and maximum in the tree annotate' :: Tree b Int -> (Tree (Int,Int) Int, Int, Int) Leaf x) = (Leaf x, x, x) annotate' (Node l _ r) = let (l',lmin,lmax) = annotate' l annotate' (= annotate' r (r',rmin,rmax) = min lmin rmin mi = max lmax rmax ma in (Node l' (mi,ma) r', mi, ma)
Write a function
withDepth
that annotates the tree by its depth. The depth of a nodev
is the length of the path from the root tov
.withDepth :: Tree a b -> Tree (a,Int) (b,Int) = withDepth' 0 withDepth withDepth' :: Int -> Tree a b -> Tree (a,Int) (b,Int) Leaf x) = Leaf (x,d) withDepth' d (Node l x r) = Node (withDepth' (d+1) l) (x,d) (withDepth' (d+1) r) withDepth' d (
Write a function
trimWhen :: (a -> Bool) -> (b -> Bool) -> Tree a b -> Tree (Tree a b) b
that ‘trims’ the subtree depending on two predicatesp :: a -> Bool
andq :: b -> Bool
. In particular, predicatep x
returns True if and only if we should trim the leaf storing some valuex
andq y
returns True if and only if the subtree whose root stores ay
should be trimmed.trimWhen :: (a -> Bool) -> (b -> Bool) -> Tree a b -> Tree (Maybe (Tree a b)) b = case t of trimWhen p q t Leaf x | p x -> Leaf (Just t) | otherwise -> Leaf Nothing Node l y r | q y -> Leaf (Just t) | otherwise -> Node (trimWhen p q l) y (trimWhen p q r)
6.write a function bimapTree :: (a -> c) -> (b -> d) -> Tree a b -> Tree c d
.
bimapTree :: (a -> c) -> (b -> d) -> Tree a b -> Tree c d
= case t of
bimapTree f g t Leaf x -> Leaf (f x)
Node l x r -> Node (bimapTree f g l) (g x) (bimapTree f g r)
Write a function
trim :: Int -> Tree a b -> Tree (Maybe (Tree a b) b)
that trims a tree at the given depth.trim :: Int -> Tree a b -> Tree (Maybe (Tree a b)) b = bimapTree f fst . trimWhen p p . withDepth trim d where p :: (c,Int) -> Bool = d' == d p (_,d') Nothing = Nothing f Just t) = Just $ bimapTree fst fst t f (
TT-Trees
Define a Tree type
TTTree a
that models trees in whichthe leaves store values of type
a
,internal nodes either have 2 or 3 children, and
internal nodes store an ‘Int’ denoting the size (number of leaves) in the subtree.
data TTTree a = Leaf a | Node2 Int (TTTree a) (TTTree a) | Node3 Int (TTTree a) (TTTree a) (TTTree a)
Define a function
insert
that inserts a new element in aTTtree
, while maintaining the subtree size invariant, and while keeping the height low (e.g. try to avoid increasing the height if possible).Define
mapTTTree
andfoldTTTree
functions for yourTTTree
data type.foldTTTree :: (a -> b) -> (Int -> b -> b -> b) -> (Int -> b -> b -> b -> b) -> TTTree a -> b = case t of foldTTTree f g2 g3 t Leaf x -> f x Node2 s l r -> g2 s (foldTTTree f g2 g3 l) (foldTTTree f g2 g3 r) Node3 s l m r -> g3 s (foldTTTree f g2 g3 l) (foldTTTree f g2 g3 m) (foldTTTree f g2 g3 r) = foldTTTree (Leaf . f) Node2 Node3 mapTTTree f
Define function
sized
that, given anInt
\(n\), returns all subtrees of size \(n\).It is not possible to write the
sized
function directly usingfoldTTTree
. However, we can usefoldTTTree
to do most of the work; that is, we can define a functionsized'
usingfoldTTTree
such thatsized :: Int -> TTTree a -> [TTTree a] = snd . sized' n sized n
write the function
sized'
sized :: Int -> TTTree a -> (TTTRee a, [TTTree a]) = foldTTTree f g2 g3 sized n where = if n == s then [t] else [] singleton s t = let t = Leaf x f x in (t,singleton s t) = let t = Node2 s l r g2 s (l,ls) (r,rs) in (t, singleton s t ++ ls ++ rs) = let t = Node3 s l m r g3 s (l,ls) (m,ms) (r,rs) in (t, singleton s t ++ ls ++ ms ++ rs)
A
TTTree
is valid if all root to leaf paths are equally long. Write a functionheight
that computes the height of aTTtree
if it is valid. Think about a suitable type for your function.height :: TTTree a -> Maybe Int = foldTTTree (\_ -> Just 0) height -> inc $ lh <.> rh) (\_ lh rh -> inc $ lh <.> mh <.> rh) (\_ lh mh rh where Nothing = Nothing inc Just h) = Just (h+1) inc ( Nothing <.> _ = Nothing Just h <.> Nothing = Nothing Just h <.> Just hr | h == hr = Just h | otherwise = Nothing
Red-Black Trees
Write a function validRBTree :: RBTree a -> Bool
that checks if a
given RBTree a
satisfies all red-black tree properties.
Complete Binary Trees
Consider the following data type of binary trees Tree a
that we
intend to use to implement binary search trees. We will store “real”
elements (the elements we care about) only in the Leaves of the
tree. The a
field in a Node
is used only as a routing element (to
guide searches).
data Tree a = Leaf a
| Node (Tree a) a (Tree a)
deriving (Show,Read,Eq)
We can compute the elements we care about of such a tree as follows:
elems :: Tree a -> [a]
Leaf x) = [x]
elems (Node l _ r) = elems l ++ elems r elems (
An example of such a trees we will care about is
= Node (Node (Leaf 1) 3 (Node (Leaf 4) 6 (Leaf 7))) 8 (Node (Leaf 9) 10 (Leaf 13)) exampleTree
Then elems exampleTree = [1, 4, 7, 9, 13]
Here, the only purpose of the element 8, for example, is to signal that all the elements in the left subtree are \(\leq 8\) and that all the elements in the right subtree are \(> 8\).
Write a function
complete
that constructs a complete balanced binary search tree out of an sorted list of \(2^h\), with \(h \geq 0\), elements (with those elements in the same order as given.).-- | This runs in O(n\log n) time. complete :: [a] -> Tree a = Leaf x complete [x] = let (ls,rs) = splitAt (n `div` 2) xs complete xs = length xs n in Node (complete ls) (last ls) (complete rs)
Bonus: Write
complete
so that it runs in linear time.Give the type of a function
delete
, such that, given an elementa
and treet
,delete a t
looks whethera
is present int
and if so, removesa
fromt
. The function delete should always be able to produce a valid element of the result type, i.e. it may not produce an error.delete :: Ord a => a -> Tree a -> Maybe (Tree a)
Please implement the above function
delete
.= case t of delete x t Leaf y | x == y -> Nothing | otherwise -> Just t Node l k r | x <= k -> Just $ case delete x l of Nothing -> r Just l' -> Node l' k r | otherwise -> Just $ case delete x r of Nothing -> l Just r' -> Node l k r'
Use higher order functions (i.e.
foldr
,foldl'
,map
,filter
) to write a functionbatchDelete
that removes all elements from a given list from a tree. Give the type of this function as well.batchDelete :: Ord a => [a] -> Tree a -> Maybe (Tree a) = foldr (\x mt -> mt >>= \t -> delete x t) (Just t) xs batchDelete xs t where -- This funny operator is called "bind" and is actually defined in -- the prelude. It is the part of the Monad instance/definition of -- the 'Maybe' type. (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b Nothing >>= _ = Nothing Just x) >>= f = f x (