Post order for a general tree? (Haskell) - haskell

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.

Related

Zipping tuples inside Haskell tree

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.

General Tree in Haskell = Rose Tree? Postoder for a rose tree?

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

Can this implementation of in-order traversal of a binary tree be improved?

I wrote a straightforward in-order-traversal function (toList1) for a binary tree. However, I worry about its complexity (memory / time). Is there a better way to implement it?
data Tree a = Empty | Node a (Tree a) (Tree a)
toList1 :: (Tree a) -> [a]
toList1 Empty = []
toList1 (Node x lx rx) = (toList lx) ++ [x] ++ (toList rx)
Haskell's append ++ performs linearly in the length of its left argument, which means that you may get quadratic performance if the tree leans left.
One possibility would be to use difference list.
Another one would be to define a Foldable instance:
data Tree a = Empty | Node a (Tree a) (Tree a)
instance Foldable Tree where
foldr f z Empty = z
foldr f z (Node a l r) = foldr f (f a (foldr f z r)) l
then, in-order-traversal comes out naturally:
toList :: Tree a -> [a]
toList = foldr (:) []
and
\> let tr = Node "root" (Node "left" Empty Empty) (Node "right" Empty Empty)
\> toList tr
["left","root","right"]

Checking if an element exists in a tree

I defined a tree as follows and want to check if a given element is an element of a given tree or not. Here's the code I have, but it doesn't work fully. It only seems to work on the head.
I'm new to Haskell and can't figure out how to fix this.
data MyTree a = Leaf a | Node [MyTree a] deriving (Eq)
isElem :: (Eq a) => MyTree a -> MyTree a -> Bool
isElem (Node []) _ = error
isElem (Node (h:t)) (Leaf a)
| (Leaf a) `elem` (h:t) = True
| otherwise = False
Here's my second attempt.
isElem :: (Eq a) => MyTree a -> MyTree a -> Bool
isElem (Node []) a = False
isElem (Node (h:t)) a
| (a == h) = True
| otherwise = (isElem (Node t) a)
I assume you're interested in implementing the function yourself (and bheklir addressed that), but you could also just derive it automatically:
{-# LANGUAGE DeriveFoldable #-}
import qualified Data.Foldable as F
data MyTree a = Leaf a | Node [MyTree a] deriving (Eq, F.Foldable)
isElem = F.elem
If we had a binary tree
data BinTree a
= Empty
| Branch a (BinTree a) (BinTree a)
deriving (Eq, Show)
Then we could do a search as
isElem :: (Eq a) => a -> BinTree a -> Bool
isElem a Empty = False
isElem a (Branch c left right)
| a == c = True
| otherwise = isElem a left || isElem a right
Notice how in the second guard, I recursively call isElem on both the left and the right leaves. If one of them returns True, then the overall return value will be True because of the logical or (||). This recursion is the key to the algorithm.
I'd like you to think about how to apply recursion to not just 2 branches, but N branches, then combine them using or. Additionally, I would recommend that you define the function as
isElem :: (Eq a) => a -> MyTree a -> Bool
And to avoid the use of error. This function should never error. Either an element is in the tree or it isn't, there isn't a third state it could be in. Just return False instead.
In this answer, I explain how to implement isElem from scratch by following the structure of the datatype MyTree.
Following the structure
Your isElem function should look for an element all over a MyTree, so probably the structure of isElem should be similar to the structure of MyTree.
data MyTree a = Leaf a | Node [MyTree a]
To make the structure of MyTree clearer, let's call [MyTree a] a forest, because a forest contains multiple trees.
data MyTree a = Leaf a | Node (MyForest a)
type MyForest a = [MyTree a]
Now we have two types, and this helps us understand that we need two functions:
isTreeElem :: MyTree a -> a -> Bool
isForestElem :: MyForest a -> a -> Bool
I changed the second argument from MyTree a to a, as proposed in bheklilr's answer.
Implementing isTreeElem
Let's start with isTreeElem. We follow the structure of MyTree by pattern matching:
isTreeElem (Leaf x) y = ...
isTreeElem (Node forest) y = ...
In the equation for Leaf, there is only one location in the tree where the y could be. So we return True if x == y and False if x /= y. In other words:
isTreeElem (Leaf x) y = x == y
In the equation Node, we need to keep searching for y in the whole forest. So we simply call isForestElem.
isTreeElem (Node forest) y = isForestElem forest y
This is the first place where our decision to introduce MyForest and isForestElem pays out: We can follow the structure of trees without thinking about forests. In this case, we see that a node contains a forest, so we immediately know that isTreeElem (Node ...) should call isForestElem. To implement this, we don't have to think about what forests are or how isForestElem works, because these decisions are encapsulated in the isForestElem function.
Implementing isForestElem
At some point, we also need to implement isForestElem. A forest is just a list, so we follow the structure of [...] by pattern matching:
isForestElem [] y = ...
isForestElem (tree : forest) y = ...
In the case for [], there is no place left to search for y, so we return False:
isForestElem [] y = False
In the case for tree : forest, the y could either be in the tree or in the forest, so we call the corresponding functions and combine their result with the or operator ||:
isForestElem (tree : forest) y = isTreeElem tree y || isForestElem forest y
The is the second place where our decision to introduce MyForest and isForestElem pays out: We can follow the structure of forests without thinking about trees. In this case, we see that a forest contains a tree, so we immediately know that isForestElem (... : ...) should call isTreeElem. To implement this, we don't have to think about what trees are or how isTreeElem works, because these decisions are encapsulated in the isTreeElem function.
Note that we could have implemented isForestElem first and isTreeElem second without changing any of the reasoning.
The code
Here's what we have so far:
data MyTree a = Leaf a | Node (MyForest a)
type MyForest a = [MyTree a]
isTreeElem :: MyTree a -> a -> Bool
isTreeElem (Leaf x) y = x == y
isTreeElem (Node forest) y = isForestElem forest y
isForestElem :: MyForest a -> a -> Bool
isForestElem [] y = False
isForestElem (tree : forest) y = isTreeElem tree y || isForestElem forest y
Using list functions
If you want to write more functions that operate on MyTree, you can follow this recipe of always implementing a forest and tree version of every function. But at some point, you might notice that the forest versions are all very similar and kind-of boring. They feel like boilerplate that doesn't contribute a lot to your programs, but needs to be written anyway. If and when that's the case, you might want to use the list operations from the Prelude and Data.List modules instead of writing your own forest operations. For example:
isForestElem forest x = any (\tree -> isTreeElem tree x) forest
Or if we change the argument order of isTreeElem and isForestElem, we can even write:
isTreeElem :: a -> Tree a -> Bool
isTreeElem = ...
isForestElem :: a -> Forest a -> Bool
isForestElem x = any (isTreeElem x)
Now isForestElem is so simple that we might want to inline it into isTreeElem:
isTreeElem :: a -> MyTree a -> Bool
isTreeElem y (Leaf x) = x == y
isTreeElem y (Node forest) = any (isTreeElem y) forest
At some point, you should start to write code that is more like the last version of isTreeElem. But as an intermediate step, while you're learning Haskell (and functional programming?), you might want to focus on code like the firest version above, with separate isTreeElem and isForestElem functions. If you carefully structure your data types, the simple principle that the structure of the code should follow the structure of the data can get you a long way.
PS. By the way, the deriving Foldable trick in András Kovács's answer is also following the structure of the datatype, but automates it more.

Haskell Tree help

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.

Resources