Could anyone please help me with my assignment questions? I've done most of it but I'm still stuck on these 3 questions.
Here is the question:
Consider the following types of search trees and balanced trees
data STree = Leaf | Node STree Int STree
data Btree = Tip Int | Branch Btree Btree
whose constructors are subject to the following constraints:
Values of the form Node left n right must have all integers in left being at most n and all integers in right being greater than n.
Values of the form Branch left right must have a difference between the numbers of integers in left and right of at most one.
a) Define a recursive function stree :: [Int] -> STree that constructs a search tree from a list of integers.
b) Define a recursive function btree :: [Int] -> BTree that constructs a balanced tree from a non-empty list of integers.
c) Using merge, define a recursive function collapse :: BTree -> [Int] that collapses a balanced tree to give a sorted list of integers.
Please help me!!!
Thanks very much in advance!
Don't want to take all the fun, but here is my go at part a.
stree :: [Int] -> Stree
stree [] = Leaf
stree (x:xs) = let (left, right) = partition (<= x) xs
in Stree (stree left) x (stree right)
It just takes the components that should be on the left and right and recursively builds the subtrees for each.
Assuming the use of sort is legit, then I'm pretty certain this works for part b.
btree :: [Int] -> Btree
btree (x:[]) = Tip x
btree xs = let len = length xs `div` 2
ys = sort xs
in Branch (btree (take len ys)) (btree (drop len ys))
stree = foldr insert Leaf
where insert :: Int -> STree -> STree
insert i (Node l i' r) | i <= i' = Node (insert i l) i' r
| otherwise = Node l i' (insert i r)
insert i (Leaf) = Node Leaf i Leaf
This isn't a very efficient solution, nor does it produce a very balanced tree, but it's a good example of how to iteratively build a data structure in Haskell. Using foldr to handle the iteration for us, we insert one element at a time into the tree, passing the new tree into the function that builds the next. We descend through the tree, until we find a leaf, and replace that Leaf with a Node to hold the given value.
These are recursive data structures. Let's start with the Search Tree:
data STree = Leaf | Node STree Int STree
and all values in the left must be less than the parent, which must be less than all values in the right. Can you write down the answers for stree [] and stree [x]? How far can you go?
I'll start:
stree [] = Leaf
stree [x] = Node Leaf x Leaf
stree ([x,y]) = if x < y then Node Leaf x (Node Leaf y Leaf) else Node (Node Leaf y Leaf) x Leaf
That sort of nested if and node construction is going to get awful pretty fast. What common sub-expressions can we factor out?
singleton x = Node Leaf x Leaf
That makes life a little easier:
stree [] = Leaf
stree [x] = singleton x
stree ([x,y]) = if x < y then Node Leaf x (singleton y) else Node (singleton y) x Leaf
But it doesn't attack the basic problem of the nested if. One common trick for lists is to take them one element at a time. Can that work for us?
addToSTree :: Int -> STree -> STree
addToStree x Leaf = singleton x
addToStree x (Node left n right) | x < n = ...
| otherwise = ...
Can you fill in the dots above? Once you have that, then it'll be time to make a loop over the contents of the list.
BTree can be solved similarly.
Related
I'm seeking any suggestion how to solve a problem with a binary search tree in Haskell. It has declaration as follows:
data TreeMap v = Leaf | Node { pair::(Integer, v), l::TreeMap v, r::TreeMap v} deriving (Show, Read, Eq, Ord)
Now I want to zip all pairs to have them as array elements. My solution so far is
listMyTuples :: TreeMap v -> [(Integer, v)]
listMyTuples Leaf = []
listMyTuples (Node pair Leaf tree2) = pair : listMyTuples tree2
listMyTuples (Node pair tree1 Leaf) = pair : listMyTuples tree1
...other pattern matching needed
I'm barely to complete that due to some lack of comprehension what to do in a case of missing leafs. So, how to make some kind of functional brigde between two subtrees to get it right?
Why pattern match on the subtrees? You can just use Node pair t1 t2. Indeed:
listFromTree :: TreeMap v -> [(Integer, v)]
listFromTree Leaf = []
listFromTree (Node pair t1 t2) = pair : listFromTree t1 ++ listFromTree t2
Here we use (++) :: [a] -> [a] -> [a] to append two lists together.
In case one of the two subtrees is a Leaf, then this will result in an empty list, and appending with an empty list, results in the other list.
Given a tree that looks like this:
data Tree a = Leaf | Node (Tree a) a (Tree a)
And a fold function that looks like this:
foldTree :: (b -> a -> b -> b) -> b -> Tree a -> b
foldTree _ b Leaf = b
foldTree fn b (Node lt x rt) = f (foldTree fn b lt) x (foldTree fn b rt)
I want to be able to write a takeWhileTree function that looks like this:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
I want it to mimic the 'normal' list takeWhile function so that it returns the largest possible tree whose elements satisfy the given condition.
So, if a tree t = Node (Node Leaf 10 Leaf) 4 (Node Leaf 5 Leaf), then:
treeTakeWhile (> 5) T = Leaf
treeTakeWhile (>= 4) T = T
treeTakeWhile (< 5) T = Node Leaf 4 Leaf
treeTakeWHile (< 8) T = Node Leaf 4 (Node Leaf 5 Leaf)
So far I seem to not be able to formulate what to pass into foldTree.
In the definition of foldtree, the function can be broken down as: b probably being the left subtree, a probably being the value in the current node and b probably being the right subtree.
Therefore, the function passed to treeTakeWhile has to be applied to all these parts of the node in some manner while being able to stop when the operation no longer applies.
treeTakeWhile fn = foldTree (\xs x ys -> if y then g else Leaf) Node()
where g = (lt, x, rt)
y = fn (Node lt x rt)
The above is clearly wrong but I am not sure how to express the act of applying the function to the current node's value followed by the left tree and the right tree here. Could somebody point me in the right direction? And how will the fold be able to produce the required tree?
Edit 1:
Okay, based on your feedback, I have gotten to a place where I think I am pretty close to the answer but cannot figure out why the compiler still complains:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
treeTakeWhile c = foldTree f acc
where acc = Leaf
f l x r = if c x then Node (f lt) x (f rt) else Leaf
As far as I can tell, foldTree is being passed the right arguments now. And the predicate is also being evaluated as required at each level of the tree. The return value is always of type Tree as well.
Instead of using foldTree immediately, let's first aim to define the function itself.
Basically there are three options here:
the tree is a Leaf, regardless what the condition is, the result is a Leaf as well;
the tree is a Node and the condition is satsified, then we yield the element, and recurse on the subtrees;
the tree is a Node and the condition is not satisfied, then the result is a Leaf.
We can encode these rules as:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
treeTakeWhile c = go
where go Leaf = Leaf -- (1)
go (Node l x r) | c x = Node (go l) x (go r) -- (2)
| otherwise = Leaf -- (3)
this then yields the expected results:
Prelude> treeTakeWhile (>5) t
Leaf
Prelude> treeTakeWhile (>=4) t
Node (Node Leaf 10 Leaf) 4 (Node Leaf 5 Leaf)
Prelude> treeTakeWhile (<5) t
Node Leaf 4 Leaf
Prelude> treeTakeWhile (<8) t
Node Leaf 4 (Node Leaf 5 Leaf)
Moving this to a foldTree
Now we aim to move the logic to a foldTree, we can thus write the function as:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
treeTakeWhile c = foldTree f x0
where f tl x tr = -- ...
x0 = -- ...
The x0 is the value we should fill in for Leafs, but we already know what that is: it is the first rule (1) and we should thus return a Leaf as well.
For f we need a function Tree a -> a -> Tree a -> Tree a. The first operand tl is the treeTakeWhile of the left subtree (this would be equivalent to go l in the original function implementation), the second parameter x is the value encoded in the Node, and the last parameter tr is the result of treeTakeWhile on the second subtree (so equivalent to go r), so:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
treeTakeWhile c = foldTree f x0
where f tl x tr = -- ...
x0 = -- ...
(leave this as an exercise).
I was supposed to create a data structure for a Tree, where every Node has an undefined amount of branches. I am guessing this will be a rose tree.
data GTree a = Node a [GTree a]
Now I am supposed to write a postorderG function that will give me a list of all my elements in my general in a postorder sequence
I wrote this but it does not seem right... Could someone help me?
postorderG :: GTree a -> [a]
postorderG (Node x l r) = postorder l ++ postorder r ++ [GTree x]
GTree is a type constructor, not a data constructor; a tree would be created with Node x [], not GTree x.
However, you don't need to create a tree at all here. You just need a the value stored at the root of the input tree for the final list in the return value.
postorderG :: GTree a -> [a]
postorderG (Node x ch) = concatMap postorderG ch -- [a]
++ [x] -- [a], not [GTree a]
If you wanted to, you could create a singleton tree to append to ch, the apply postOrderG to each child and the new singleton in order.
postorderG (Node x ch) = concatMap postorderG (ch ++ [Node x []])
Taking advantage of the [] monad instead of using concatMap, the RHS would look like either
(ch >>= postorderG) ++ [x]
or
(ch ++ [Node x []]) >>= postorderG
I asked this question earlier, but I did not know the difference between a rose tree and general tree. Now I know that the data structure is slightly different.
data GTree a = Leaf a | Branch [GTree a]
I would like to write a postorderG function that would give me a list with all the elements of Gtree in postorder.
I know how to do it for a binary tree.
data BTree a = Nil | Node a (BTree a) (BTree a)
postOrder :: BTree a -> [a]
postOrder Nil = []
postOrder (Node x lt rt) = (postOrder lt) ++ (postOrder rt) ++ [x]
A GTree just has as many branches as you wish, not just two. The concept for post order traversal is still the same: visit all branches before visiting the current node. You can do this either with explicit recursion on the list of branches or with map or reduce.
I got the task of getting all leafs from a binary tree of this datatype:
data Bintree el = Empty |
Tree {left :: Bintree el, node :: el, right :: Bintree el} deriving Show
Now I have this Treefold function which works perfectly in tests:
binTreeFold :: (a -> b -> a -> a) -> a -> Bintree b -> a
binTreeFold f el Empty = el
binTreeFold f el tree#(Tree leftTree node rightTree) = f (binTreeFold f el leftTree) node (binTreeFold f el rightTree)
And I try to get all leafs but somehow it simply doesnt work (Compile issues mentioned below):
leavesWithFold :: Bintree a -> [a]
leavesWithFold Empty = []
leavesWithFold tree = binTreeFold (\left -> \node -> \right -> if (checkIfTreeIsLeaf node) then left ++ [node] ++ right else left ++ [] ++ right) [] tree
using the following function:
checkIfTreeIsLeaf :: Bintree a -> Bool
checkIfTreeIsLeaf Empty = False
checkIfTreeIsLeaf (Tree Empty node Empty) = True
checkIfTreeIsLeaf _ = False
The compiler tells me
Couldn't match type `a' with `Bintree a0'
But in former functions the use of
left ++ [node] ++ right
Was working perfectly fine. Have you any idea what I did wrong and probably what I could change?
Best Whishes
Well typically the idea of a using a fold function is that it does all the work for you. So by writing a function that branches into an Empty case and a tree case, this is already a bit strange.
A recursive approach
But let us simply start with a recursive approach. Forget about folding, etc. for now. How would we generate a list of leaves in general?
Well there are basically three cases here:
in case we encounter an Empty, then we return the empty list, since Empty is not a leaf, and we are supposed to return all leaves, so:
leaves Empty = []
in case we encounter a Tree with Empty both as left and right subtree, we know that that Tree is a leaf, so we return the element it carries, as a list:
leaves (Tree Empty x Empty) = [x]
in case one of the two subtrees (or both) are not Empty, we recursively would call the leaves function, and concatenate the two together:
leaves (Tree l _ r) = leaves l ++ leaves r
So now in full we got:
leaves :: Bintree a -> [a]
leaves Empty = []
leaves (Tree Empty x Empty) = [x]
leaves (Tree l x r) = leaves l ++ leaves r
How to detect through recursion that this is a leaf
We of course can not do that with the binTreeFold approach. But can't we detect whether a tree is in fact a leaf? In case the two recursive calls both result in an empty list, we know that the current Bintree is in fact a leaf. Indeed: if the left (and right) subtree are Empty, they result in empty lists. And in case these are not empty, then these either are leaves, that will recursively produce a singleton list, or those are not Trees with descendants, that will eventually lead to leaves, and therefore to non-empty lists.
Encoding this in the fold function
So we an first take a look at the recursive calls, and then based on the fact whether these are both empty lists, either return a singleton list with the leaf element, or concatenate the two lists together, like:
f [] x [] = [x]
f l _ r = l ++ r
Or using this in the binTreeFold function:
leavesWithFold :: Bintree a -> [a]
leavesWithFold = binTreeFold f []
where f [] x [] = [x]
f l _ r = l ++ r