Check if binary tree is complete - haskell - haskell

I have a binary tree:
data Btree a = Leaf a | Unary (Btree a) a | Binary (Btree a) a (Btree a) deriving Show
and some examples to work with:
ex1 = Binary (Binary (Leaf 0) 1 (Leaf 2)) 3 (Unary (Leaf 4) 5)
ex2 = Binary (Unary (Leaf 1) 2) 3 (Binary (Leaf 4) 5 (Leaf 10))
ex3 = Binary (Binary (Leaf (0,"a"))(1,"z")(Leaf (2,"x")))(3,"y")(Binary (Leaf (4,"b"))(5,"c")(Leaf (6,"d")))
I need to find out whether the tree is complete or not, a tree is complete if the distance between the root and any leaf is always the same up to 1, all of the deepest leaves are located to the left of the others, and there is at most one internal node with unary node that should be located on the second-to-last level.
This is what i have so far
complete :: Btree a -> Bool
complete x = fst $ go x where
go (Leaf _) = (True, 0)
go (Unary left _) = (leftTrue, 1 + leftCount) where
(leftTrue, leftCount) = go left
go (Binary left _ right) = (leftTrue && rightTrue &&
leftCount == rightCount,
1 + leftCount + rightCount) where
(leftTrue, leftCount) = go left
(rightTrue, rightCount) = go right
ex1 & ex3 should return true, but only ex3 is. I believe the Unary part is the issue.

This answer counts on a code change in the Unary part like that: (leftTrue, 1 + leftCount) -> (False, 1 + leftCount).
The body of your solution is the go function.
The function returns for a subtree
if the left and right subtrees are completely balanced and how many nodes the subtree has.
All depths are the same, like in the ex3.
But if you don't have 2^n-1 nodes and 2^(n-1) leaves, it is impossible to build that tree.
In the description of your problem is allowed little disbalance allowing represent any count of nodes.
Ex1 fulfills the rules ex2 doesn't.
Ex3 is also complete according to your definition.
Under the code, I made ASCII art to the examples.
My solution doesn't count amount nodes of subtrees. It calculates maximal and minimal depths because it allows me to reveal illegal disbalance in any level of a tree.
The boolean value says if the subtree accomplishes your conditions of the complete tree.
It checks that:
differences are the same up to one
the left subtree has a greater or the same minimal depth as the maximal depth of the right tree.
Checks above also contain the condition about one unary node on the second-to-last level.
Can you guess what belongs to the place ...?
data Btree a = Leaf a | Unary (Btree a) a | Binary (Btree a) a (Btree a) deriving Show
ex1 = Binary (Binary (Leaf 0) 1 (Leaf 2)) 3 (Unary (Leaf 4) 5)
ex2 = Binary (Unary (Leaf 1) 2) 3 (Binary (Leaf 4) 5 (Leaf 10))
ex3 = Binary (Binary (Leaf (0,"a"))(1,"z")(Leaf (2,"x")))(3,"y")(Binary (Leaf (4,"b"))(5,"c")(Leaf (6,"d")))
complete :: Btree a -> Bool
complete x = fst $ go x
go :: Btree a -> (Bool,(Int,Int))
go (Leaf _) = (True, (0, 0))
go (Unary left _) = (leftMaxDepth == 0, (1 + leftMaxDepth, 0)) where
(leftIs, (leftMaxDepth, leftMinDepth)) = go left
go (Binary left _ right) =
( leftIs && rightIs
...
, (1+newMaxDepth
, 1+newMinDepth )) where
newMaxDepth = max leftMaxDepth rightMaxDepth
newMinDepth = min leftMinDepth rightMinDepth
(leftIs, (leftMaxDepth, leftMinDepth)) = go left
(rightIs, (rightMaxDepth, rightMinDepth)) = go right
&& leftMinDepth >= rightMaxDepth && newMaxDepth - newMinDepth <= 1
ex1: True
3
/ \
/ \
1 5
/ \ /
0 2 4
Depths: [3,3,3,2]
ex2: False
3
/ \
/ \
2 5
/ / \
1 4 10
Depths: [3,2,3,3]
ex3: True
(3,"y")
/ \
/ \
(1,"z") (5,"c")
/ \ / \
(0,"a") (2,"x") (4,"b") (6,"d")
Depths: [3,3,3,3]

This answer counts on a code change in the Unary part like that: (leftTrue, 1 + leftCount) -> (False, 1 + leftCount).
https://web.cecs.pdx.edu/~sheard/course/Cs163/Doc/FullvsComplete.html
Full binary rtee:
Complete binary tree:
Your solution counts on a full binary tree.
Your exercise is about checking if the binary tree is complete.
The algorithm is fine, but the check leftCount == rightCount should be changed.
A full binary tree has a minimum depth equal to the maximum depth,
and the left subtree has the same number of nodes as the right.
In a complete binary tree, the situation is more difficult:
Let the number of nodes complete binary tree is x then
x = 2^m-1+n, where m is the minimum depth of the tree and 0 <= n < 2^(m+1) .
Let '1' be the suffix of the left subtree and the suffix '2' of the right.
for subtrees of a complete binary tree, it always holds:
If the minimum depths of the left and right subtrees are the same, then the right tree must be full.
If the minimum depth of the left subtree is equal to the minimum depth of the right subtree plus one, then the left subtree must be full.
getMinDepthAndRest :: Int -> (Int,Int)
getMinDepthAndRest x = getMinDepthandRest' x 0
getMinDepthAndRest' :: Int -> Int -> (Int,Int)
getMinDepthAndRest' x m'
| x < 2^m'-1 = (m'-1,x-2^(m'-1)+1)
| otherwise = getMinDepthandRest' x (m'+1)
complete :: Btree a -> Bool
complete x = fst $ go x where
go (Leaf _) = (True, 1)
go (Unary left _) = (leftCount == 1, 1 + leftCount) where
(leftTrue, leftCount) = go left
go (Binary left _ right) = (leftTrue && rightTrue &&
(m1==m2 && n2==0) || (m1==m2+1 && n1==0),
1 + leftCount + rightCount) where
(m1,n1) = getMinDepthAndRest leftCount
(m2,n2) = getMinDepthAndRest rightCount
(leftTrue, leftCount) = go left
(rightTrue, rightCount) = go right

Related

(Can I?) How can I access the int value of the next node (tree recursion)

So I have a tree defined as follows:
data Tree = Node Tree Int Tree | Leaf Int
The Int for a Node in this case is the value at that Node. I am trying to check that a tree is balanced, and that the tree is increasing as it's traversed left to right.
To do so I have a recursive function that takes a (Node left x right) and checks that the difference in height of left and right (the nodes below it) is no more than one. I then call balanced again for left and right.
Is it possible to access the Int value of left and right?
Yes, you can write a function that returns the integer at the top node:
getInt (Node _ i _) = i
getInt (Leaf i) = i
E.g.
Prelude> getInt $ Leaf 42
42
Prelude> getInt $ Node (Leaf 42) 123 (Leaf 1337)
123
Of course you can, instead of put variables like left and right, use the constructors again:
Edit, I forget the case of Leaf, it has also an int:
data Tree = Node Tree Int Tree | Leaf Int
exampleSumNodes (Node left x right) = (treeToInt left) + x + (treeToInt right)
treeToInt (Node _ n _) = n
treeToInt (Leaf n ) = n

build a tree with given number of nodes

I have a datastructure for a tree with nodes that have either one or two childs. I can generate a random tree with a given maximum Depth. Now I want to generate these random three with a given maximum amount of nodes (/leafes). This is my structure:
import System.Random
data Tree a = Leaf
| NodeTwo (Tree a) (Tree a)
| NodeOne (Tree a)
deriving (Show)
create :: RandomGen g => Int -> Int -> Int -> Int -> g -> Tree a
create depth maxNodeOne maxNodeTwo maxLeaf g
| (depth == 0) = Leaf
| (x >= a && x < c && (maxNodeTwo /= 0))
= let (g1, g2) = split g in
NodeTwo (create (depth -1) maxNodeOne (maxNodeTwo-1)
maxLeaf g1) (create (depth -1) maxNodeOne
(maxNodeTwo-1) maxLeaf g2)
|(x >= c && x < 2*c && (maxNodeOne /= 0))
= NodeOne (create (depth -1)
(maxNodeOne -1) maxNodeTwo maxLeaf g')
| otherwise = Leaf
where (x, g') = next g
(a, b) = genRange g
c = (b - a) `div` 3
countFnk :: Tree a -> Int
countFnk (Leaf) = 0
countFnk (NodeOne a) = countFnk a
countFnk (NodeTwo a b) = 1 + countFnk a + countFnk b
countLam :: Tree a -> Int
countLam (Leaf) = 0
countLam (NodeOne a) = 1 + countLam a
countLam (NodeTwo a b) = countLam a + countLam b
countLeaf :: Tree a -> Int
countLeaf (Leaf) = 1
countLeaf (NodeOne a) = countLeaf a
countLeaf (NodeTwo a b) = countLeaf a + countLeaf b
This attempt fails ofcourse. I don't know how to decrement the counter(s) for the node(s) in the recursion. I also have functions which can get me the amount of nodes (/leafes) but I don't know how to use these functions in my create function since they need a finished tree to scan.
Thanks for your help.
The most obvious problem is in your NodeTwo case. You arrive at that point with a "budget" of NodeTwos and NodeOnes to spend. But you tell both branches of your new tree the same thing: "feel free to spend the whole total budget"! Of course if they both do that, you will wind up spending double your budget.
You need some way to negotiate a budget for each branch of the tree. There are a number of ways you could do this; for example, give one branch access to the whole budget, and give whatever is left to the second branch. Or you could decide before creating either branch how to divide the budget between them, and give each branch only a portion of your total budget.
Either of those two approaches probably introduce some bias in your randomness, which may or may not matter to you. You should think of a way to handle the budget accounting in a way that produces the kinds of random trees you want.
Once you've fixed this, you'll run into other problems: there are constraint sets for which it is impossible to build a tree fitting them! Most notably, if maxLeaf is zero, you can't create any kind of tree at all, since every tree has at least one leaf node somewhere. You'll have to be careful not to build any subtrees with too few leaves available to let them terminate.

Finding out number of even paths from root in a tree

I'm trying to get a function that counts all paths from the root to a leaf that has an even number of nodes ( counting the root and the leaf)
My tree looks like this:
data Tree = Leaf Int | Node Int Tree Tree
all i got so far is a function that counts ALL nodes in a tree, which is easy enough:
countNodes (Leaf _) = 1
countNodes (Node _ x y) = 1+ countNodes x + countNodes y
Now i saw a bunch of questions that deal with trees but i felt like no answer helped me much, so I'm just gonna ask myself. How do i make a part of a function stop when a leaf is reached? I know this has to do with my problem to think with recursions.
What I tried to do was to to make list of all paths from the root, but i always end up with a function that gets all elements in the tree and puts them together somehow.
I'm missing something simple, please help. (or link me an answer that does exactly what i want)
I think the easiest way would be to make a data type that can describe a path through a tree:
data Path = L Path | R Path | End deriving (Eq, Show)
This type is basically a list but with two prepend constructors to tell you either go Left or go Right. This conveniently lets you look up items by path, or you can write a function that gives you a list of all paths in the tree.
-- Note that this can fail: lookupNode (Leaf 1) (L End) == Nothing
lookupNode :: Tree -> Path -> Maybe Tree
allPaths :: Tree -> [Path]
If you can write the allPaths function, then you can write the function you want on top of it. To start, just begin by listing the base cases:
allPaths (Leaf _) = [End]
allPaths (Node _ left right) = _
To fill in the hole _, think about what it means to list all the paths starting at a Node and recursing down left. You would need to have a L at the beginning of all of those paths, so you can put the following in there
allPaths (Node _ left right) = (map L $ allPaths left)
Similarly, you would need to handle the right tree:
allPaths (Node _ left right) =
(map L $ allPaths left) ++
(map R $ allPaths right)
So now:
> let tree =
Node 1
(Node 2 -- L _
(Leaf 3) -- L (L End)
(Node 4 -- L (R _)
(Leaf 5) -- L (R (L End))
(Leaf 6) -- L (R (R End))
)
)
(Leaf 7) -- R End
> allPaths tree
[L (L End),L (R (L End)), L (R (R End)),R End]
Now, to find the Leafs with an even number of nodes above them, first write a function that calculates a path length:
pathLength :: Path -> Int
pathLength End = 0
pathLength (L rest) = 1 + pathlength rest
pathLength (R rest) = 1 + pathLength rest
evenNodeCountPaths :: Tree -> [Path]
evenNodeCountPaths tree = filter (even . pathLength) $ allPaths tree
Note: It is possible to do this with
data Dir = L | R | End
type Path = [Dir]
But that can lead to invalid paths like [End, End, L, R, End], which just doesn't make any sense. I chose to go for the list-like data Path for this reason. You have to write your own pathLength function, but this formulation makes it impossible to have invalid paths.
Probably it's easier to compute both the number of even and the number of odd paths.
evenAndOdd (Leaf _) = (0, 1)
evenAndOdd (Node _ l r) = let
(el, ol) = evenAndOdd l
(er, or) = evenAndOdd r
in (ol+or, el+er)
If you really must, you can then define a function in terms of this to count just the even paths.
evenOnly = fst . evenAndOdd

Maximum tree depth in Haskell

I am given this type definition:
data Tree = Leaf Char | Branch2 Char Tree Tree | Branch3 Char Tree Tree Tree
How can I write a method that gives me the maximum path length of the tree (count the nodes in the path)?
You would want to write a recursive function to do this. For each Tree constructor, you'll need a different case in your function. To start with, you know that the depth of any Leaf is 1, so
maxDepth :: Tree -> Int
maxDepth (Leaf _) = 1
maxDepth (Branch2 c left right) = maximum [???]
maxDepth (Branch3 c left center right) = maximum [???]
I'll let you finish the rest of the function. You could do it a few different ways as well (such as using max instead of maximum).
with lazy corecursive breadth-first tree traversal:
treedepth tree = fst $ last queue
where
queue = (1,tree) : gen 1 queue
gen 0 p = []
gen len ((d,Leaf _ ) : p) = gen (len - 1) p
gen len ((d,Branch2 _ l r) : p) = (d+1,l) : (d+1,r) : gen (len + 1) p
gen len ((d,Branch3 _ l c r) : p) = (d+1,l) : (d+1,c) : (d+1,r) : gen (len + ??) p
changing it to the depth-first traversal will turn it into a regular recursion.
I'd probably write a tail-recursive solution by using continuation passing.
depth :: Tree -> Int
depth t = go t id
where
go (Leaf _) k = k 0
go (Branch2 _ l r) k = go l $ \dl -> go r $ \dr -> k (1 + max dl dr)
go (Branch3 _ l m r) k = go l $ \dl -> go m $ \dm -> go r $ \dr -> k (1 + max dl (max dm dr))
depth :: Tree -> Int
depth (Leaf _) = 1
depth (Branch2 c left right) = max((depth(left) + 1) (depth(right) + 1))
depth (Branch3 c left center right) = max(max((depth(left) + 1) (depth(right) + 1)) (depth(center) + 1))
Is that right? Sorry i'm not so good in recursive programming.

Retrieving an element of a balanced binary tree in Haskell

Assuming I have a custom tree datatype of the following form:
data BalTree a = Leaf | Node Integer (BalTree a) a (BalTree a) deriving (Eq, Show, Read)
and creating a new tree of size 10, I'll get this:
Node 10 (Node 5 (Node 2 (Node 1 Leaf 'Z' Leaf) 'Z' Leaf)
'Z'
(Node 2 (Node 1 Leaf 'Z' Leaf) 'Z' Leaf))
'Z'
(Node 4 (Node 2 (Node 1 Leaf 'Z' Leaf) 'Z' Leaf)
'Z'
(Node 1 Leaf 'Z' Leaf))
How do I retrieve an element in in-order transversal when given an index?
My attempt:
ind Leaf pos = Nothing
ind tree#(Node n lt x rt) pos
| pos < 0 = Nothing
| pos > treeSize-1 = Nothing
| pos < hTreeSize = ind lt pos
| pos == hTreeSize = Just x
| pos > hTreeSize = ind rt (pos - hTreeSize)
where treeSize = size tree
hTreeSize = treeSize `div` 2
I'm not exactly sure if this is in-order transversal and it doesn't return the correct result.
We want to get the nth value stored in a binary tree in an in-order walk. We know the number of values stored in each tree rooted at each node (the Integer parameter of Node).
data BalTree a = Leaf
| Node Integer (BalTree a) a (BalTree a)
size :: BalTree a -> Integer
size Leaf = 0
size (Node size _ _ _) = size
nthInOrder :: BalTree a -> Integer -> Maybe a
nthInOrder Leaf _ =
Nothing
nthInOrder (Node _ left x right) n
| leftSize == n - 1 = Just x
| n <= leftSize = nthInOrder left n
| otherwise = nthInOrder right (n - leftSize - 1)
where
leftSize = size left
The idea is this: suppose we're at node A and want the nth value:
A
/ \
B C
If B holds n-1 values, then the nth value is that of A. If B holds more or equal than n values, then we can ignore the rest of the tree and search only B; so we just recurse into it. Otherwise, we should be looking for the value in C, so we recurse into it; in this case, we also need to update the n to reflect that there are some values in B, and 1 value in A.
In the worst case, this algorithm walks down to a Leaf, so, the complexity is O(depth of tree). If the tree is balanced, the complexity is O(log2(size of tree)).

Resources