I write the function foldTree
that build balanced binary tree from list.
I must use foldr
and it's ok, i used it, but i make insertInTree
function recursive =( for now i know only this way to walk through the trees =)).
UPDATE: iam not sure about function insertTree
: is it right calculate the heights in recursion?? =(( need some help here.
Is it possible to write insertInTree
without recursion (something with until/iterate/unfoldr
) or make foldTree
function without helper functions => shorter somehow?
this is my try below:
data Tree a = Leaf
| Node Integer (Tree a) a (Tree a)
deriving (Show, Eq)
foldTree :: [a] -> Tree a
foldTree = foldr (\x tree -> insertInTree x tree) Leaf
insertInTree :: a -> Tree a -> Tree a
insertInTree x Leaf = Node 0 (Leaf) x (Leaf)
insertInTree x (Node n t1 val t2) = if h1 < h2
then Node (h2+1) (insertInTree x t1) val t2
else Node (h1+1) t1 val (insertInTree x t2)
where h1 = heightTree t1
h2 = heightTree t2
heightTree :: Tree a -> Integer
heightTree Leaf = 0
heightTree (Node n t1 val t2) = n
output:
*Main> foldTree "ABCDEFGHIJ"
Node 3 (Node 2 (Node 0 Leaf 'B' Leaf) 'G' (Node 1 Leaf 'F' (Node 0 Leaf 'C' Leaf))) 'J' (Node 2 (Node 1 Leaf 'D' (Node 0 Leaf 'A' Leaf)) 'I' (Node 1 Leaf 'H' (Node 0 Leaf 'E' Leaf)))
*Main>
Your insertion function is in error when the two sub-trees' heights are equal, because inserting into the right sub-tree will increase its height if it was already full. It is not immediately clear to me whether such situation will ever arise or not in your code.
The apparently correct way to insert a new element into a tree seems to be
insertInTree x (Node n t1 val t2)
| h1 < h2 = Node n (insertInTree x t1) val t2
| h1 > h2 = Node n t1 val t2n
| otherwise = Node (h+1) t1 val t2n
where h1 = heightTree t1
h2 = heightTree t2
t2n = insertInTree x t2
h = heightTree t2n -- might stay the same
This creates almost balanced trees (a.k.a. AVL-trees). But it pushes each new element to the very bottom of the tree.
edit: These trees can be nicely seen with
showTree Leaf = ""
showTree n@(Node i _ _ _) = go i n
where
go _ (Leaf) = ""
go i (Node _ l c r) = go (i-1) l ++
replicate (4*fromIntegral i) ' ' ++ show c ++ "\n" ++ go (i-1) r
Try
putStr . showTree $ foldTree "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
And yes, you can write foldTree
shorter, as
foldTree = foldr insertInTree Leaf
Just want to point out that the accepted answer is good but will not work after having a height 3 balanced binary tree as it did not consider the fact that the left tree could have less height than the right after inserting.
Apparently, the code could've worked adding an extra condition:
insertInTree x (Node n t1 val t2)
| h1 < h2 = Node n t1n val t2
| h1 > h2 = Node n t1 val t2n
| nh1 < nh2 = Node n t1n val t2
| otherwise = Node (nh2+1) t1 val t2n
where h1 = heightTree t1
h2 = heightTree t2
t1n = insertInTree x t1
t2n = insertInTree x t2
nh1 = heightTree t1n
nh2 = heightTree t2n
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With