I am struggling with how to recursively traverse a binary tree in Haskell
It is rather clear how it's done when the return type is a list. But I don't get how is it done if the return type is a tree itself?
for example, if we have the tree and wish to exclude zeros:
5
/ \
0 2
/ \
0 1
and we would like to return a tree with the other numbers:
5
/ \
1 2
Then I figured you would do something like this:
modTree :: Tree -> Tree
modTree Void = Void
modTree (Node l x r)
| x == 0 = modTree l
| otherwise = Node (modTree l) x (modTree r)
My issue is that I know that this will only traverse the left side. But I fail to grasp how recursively call the function in Haskell for the entire tree.
Any suggestions would be highly appreciated.
One idea would be to bubble 0s down and left until they have no left child, then replace them with their right child. For example:
0 1 1 1
/ \ / \ / \ / \
1 2 -> 0 2 -> 3 2 -> 3 2
/ \ / \ / \ \
3 4 3 4 0 4 4
You need to take some care about what happens when there are multiple 0s on the path from root to leaf.
0
/ \
0 2
/ \
3 4
Probably the simplest (though perhaps not the most efficient) way to deal with this is to recursively drop 0s from the left child before beginning to bubble down.
0 0 0 3 3
/ \ / \ / \ / \ / \
0 2 -> 3 2 -> 3 2 -> 0 2 -> 4 2
/ \ / \ \ \
3 4 0 4 4 4
I encourage you to take a stab at implementing this yourself. If you have trouble, describing what you tried, where you got stuck, and why you think the problem you're seeing is insurmountable would make a good follow-up question.
The standard thing to do here is this:
if the root is non-zero we apply the algorithm recursively to each of its child branches and we're done (as you already indicate in your code)
if the root is zero with only one child we just return that child (transformed, of course)
if the root is zero with two child branches we apply the algorithm recursively to each of the two branches, then pull the rightmost value from the new left child and put it into the root.
To pull the rightmost value from a tree:
if it's a leaf, just remove the leaf
if it's a node, it doesn't have a right child, so just put its left child in its place
The whole thing is linear,(*) apparently.
modTree :: Tree -> Tree
modTree Void = Void
modTree (Node l x r)
| x == 0 = modZero (modTree l) (modTree r)
| otherwise = Node (modTree l) x (modTree r)
modZero Void r = r
modZero l Void = l
modZero l r = let (v, nl) = pullRightmost l in
Node nl v r
Implementing pullRightmost is left as an exercise.
(*)No spine is pulled from over more than once, because we are pulling from the tree which is already without any 0s, "after" the recursive call. So these will be another O(n) operations in total.
Related
I wonder if my complexity analysis (T worst case for n elements/nodes) is correct for the following function leaves in Haskell (Note: wurzel = root; C = constant factor)
--abstract data type for bin trees
data Bintree el = Empty
| Node {left :: Bintree el, root :: el, right :: Bintree el}
deriving Show
--extract all leaves of a given Bintree (output: list)
leaves :: Bintree el -> [el]
leaves Empty = []
leaves (Node Empty root Empty) = [root]
leaves (Node left root right) = leaves left ++ leaves right
No, there are many mistakes. Here are a few of the more glaring ones:
When you write T(n/2)+T(n/2)+T(n/4)+T(n/4)+..., you seem to be assuming that half of the nodes are in the left branch and half are in the right. That's not always true -- some trees are balanced, but some certainly are not.
Even if the tree is balanced, there are not only 2 subtrees of size n/4 -- there are 4. Similarly there are 8 subtrees of size n/8, not 2.
The correct expression to describe "dividing n by 2 i times" is n/(2^i), not n/(i^2). Additionally, the above comment about balancing notwithstanding, you would want to keep dividing until you reached just one leaf, so the correct base case of the ellipsis is T(n/n), not either one of T(n/(2^n)) or T(n/(n^2)).
If you repeatedly divide by two, and add the results, as in n + n/2 + n/4 + n/8 + n/16 + ..., forever, you get 2*n, not log_2(n).
Anyway, that doesn't apply, because you are not adding multiples of n. T(n) + T(n/2) + T(n/4) + T(n/8) + T(n/16) + ... is not necessarily related in any special way to T(2*n) (nor to T(log_2(n))). For example, imagine if f(n) = 1. Then the sum f(1) + f(1/2) + f(1/4) + f(1/8) + f(1/16) + ... = 1 + 1 + 1 + 1 + 1 + ... diverges, even though f(1 + 1/2 + 1/4 + 1/8 + 1/16 + ...) = f(2) = 1.
I'm having to create a binary expression tree for the postorder expression
XYZ+AB-C*/-
from what i know, with pupushing opperands into a stack and the popping two out when an operator is next in th list, my best attempt at the binary expression tree is this
-
/ \
X /
\
*
/ \
C -
/ \
A B
\
+
/ \
Y Z
is this correct? or am I completely wrong
Your stack shall look like this when talking about operations and their precedence.
X - ((A-B) * C) / (Y+Z)
((A-B) * C) / (Y+Z)
(A-B) * C
(A-B)
(Y+Z)
X
So the correct way is Stephan's answer.
This is my code:
module Main where
import Data.Graph.Inductive
import Data.Graph.Inductive.Example
func :: Graph gr=> gr a b ->[Node]->Int-> [(Node,Int)]
func graph (x:xs) y
|indeg graph x == 0 = (x,y+1):func (delNode x graph ) xs (y+1)
graph2:: Gr Int Int
graph2 = mkGraph (genLNodes 1 14)[(1,2,1),
(1,3,1),
(3,14,1),
(14,6,1),
(14,7,1),
(2,4,1),
(2,5,1),
(4,6,1),
(5,7,1),
(6,8,1),
(7,9,1),
(8,10,1),
(9,11,1),
(10,12,1),
(11,12,1),
(12,13,1),
(14,13,1)]
Graph2 have 14 nodes and e.g (1,2,1) means, edge from node 1 to node 2 with a weight of 1.
Func takes my Graph2, topological sorting vertices and some number e.g 0.
Func checks if inward-bound degree of the Node is equal to 0 and creates list of tuples where x is IdNode and y is increasing when indeg graph x == 0 is true. The vertex is removed
And here is my problem, I want to see if more vertices has a degree of 0 and add 1.
EDIT:
The function should act as follow:
topsort: [1,3,14,2,5,7,9,11,4,6,8,10,12,13]
check in-bound degree for each node in the list.
if degree is equal 0, add 1 to path lenght ( node 1 in-bound is equal 0 so path length= 1)
remove node from graph and check in-bound degree of nodes after removing node and return to step 2.
continuing example:
after removing node 1, nodes 2 and 3 have in-bound = 0 so I add 1 to path length (path lenght = 2 for node 2 and 3 ) and I remove node 2 and 3.
Now in-bound degree =0 have 14,4,5 so I add 1 to path length (path lenght =3) and I remove these nodes and so on
I hope that the image of the graph will help.
With lazy evaluation you can use the "tie-the-knot" method to compute the depths very declaratively:
minOr0 [] = 0
minOr0 ds = minimum ds
depths :: Graph gr => gr a b -> [(Node, Int)]
depths gr =
let pairs = [ (x, depth x) | x <- nodes gr ]
depth x = 1 + minOr0 [ d | y <- pre gr x, let Just d = lookup y pairs ]
in pairs
test2 = depths graph2
The definition between pairs and depth is circular: evaluating a tuple in pairs calls depth. Calling depth will look up other tuples in pairs. If the graph does not have any cycles the process will eventually
terminate.
Due to the way lazy evaluation works in Haskell, the calls to depth
are effectively memoized.
Let N be the number of inner nodes in a quadtree. Why is the number of leaves equal to 1 + 3 * N? I don't understand how we need to argue.
TLDR: Number of Leaf Nodes = 3 * Number of Internal Nodes + 1
I would like to build on #Sneftel's answer.
Let L1, L2, L3 refers to the number of leaf nodes when there are 1,2,3 internal nodes.
Whenever we add an internal node, there is a loss of 1 leaf node and gain of k leaf nodes (in quad k=4) from the previous value of the number of leaf nodes.
We start with the base condition
L1 = k , Just the root node k children ( k = 4 in quad tree)
For example:
L2 = L1 - 1 + k
L3 = L2 - 1 + k
Generally ,
Ln = Ln-1 -1 + k , where n is the number of internal nodes and the k is the branching factor ( k = 4 in quad tree)
Let's expand the equation
Ln = Ln-1 -1 + k
Ln = Ln-2 -1 + k -1 + k
If we keep expanding this, we will reach the base condition L1 which we know is k
Ln = L1 + ((-1 + k) + (-1 + k) .... n-1 times)
We know that the base condition L1 = k
Ln = k + ( -1 + k ) * (n - 1)
Now, Let's take a quad tree where k = 4
Ln = 4 + 3 (n - 1)
Ln = 4 + 3n - 3
Ln = 3n + 1
Number of Leaf nodes in quad tree = 3 * Number of Internal Nodes in quad tree + 1
Consider expanding a quadtree by subdividing a leaf node. That leaf node becomes an internal node (decreasing the leaf count by one), and four leaf nodes are added. If the previous number of internal nodes was N, the new number of internal nodes is N+1, and the number of leaves is 1 + 3*N - 1 + 4 = 1 + 3*(N+1). The general statement follows by induction.
I am doing problem 61 at project Euler and came up with the following code (to test the case they give):
p3 n = n*(n+1) `div` 2
p4 n = n*n
p5 n = n*(3*n -1) `div` 2
p6 n = n*(2*n -1)
p7 n = n*(5*n -3) `div` 2
p8 n = n*(3*n -2)
x n = take 2 $ show n
x2 n = reverse $ take 2 $ reverse $ show n
pX p = dropWhile (< 999) $ takeWhile (< 10000) [p n|n<-[1..]]
isCyclic2 (a,b,c) = x2 b == x c && x2 c == x a && x2 a == x b
ns2 = [(a,b,c)|a <- pX p3 , b <- pX p4 , c <- pX p5 , isCyclic2 (a,b,c)]
And all ns2 does is return an empty list, yet cyclic2 with the arguments given as the example in the question, yet the series doesn't come up in the solution. The problem must lie in the list comprehension ns2 but I can't see where, what have I done wrong?
Also, how can I make it so that the pX only gets the pX (n) up to the pX used in the previous pX?
PS: in case you thought I completely missed the problem, I will get my final solution with this:
isCyclic (a,b,c,d,e,f) = x2 a == x b && x2 b == x c && x2 c == x d && x2 d == x e && x2 e == x f && x2 f == x a
ns = [[a,b,c,d,e,f]|a <- pX p3 , b <- pX p4 , c <- pX p5 , d <- pX p6 , e <- pX p7 , f <- pX p8 ,isCyclic (a,b,c,d,e,f)]
answer = sum $ head ns
The order is important. The cyclic numbers in the question are 8128, 2882, 8281, and these are not P3/127, P4/91, P5/44 but P3/127, P5/44, P4/91.
Your code is only checking in the order 8128, 8281, 2882, which is not cyclic.
You would get the result if you check for
isCyclic2 (a,c,b)
in your list comprehension.
EDIT: Wrong Problem!
I assumed you were talking about the circular number problem, Sorry!
There is a more efficient way to do this with something like this:
take (2 * l x -1) . cycle $ show x
where l = length . show
Try that and see where it gets you.
If I understand you right here, you're no longer asking why your code doesn't work but how to make it faster. That's actually the whole fun of Project Euler to find an efficient way to solve the problems, so proceed with care and first try to think of reducing your search space yourself. I suggest you let Haskell print out the three lists pX p3, pX p4, pX p5 and see how you'd go about looking for a cycle.
If you would proceed like your list comprehension, you'd start with the first element of each list, 1035, 1024, 1080. I'm pretty sure you would stop right after picking 1035 and 1024 and not test for cycles with any value from P5, let alone try all the permutations of the combinations involving these two numbers.
(I haven't actually worked on this problem yet, so this is how I would go about speeding it up. There may be some math wizardry out there that's even faster)
First, start looking at the numbers you get from pX. You can drop more than those. For example, P3 contains 6105 - there's no way you're going to find a number in the other sets starting with '05'. So you can also drop those numbers where the number modulo 100 is less than 10.
Then (for the case of 3 sets), we can sometimes see after drawing two numbers that there can't be any number in the last set that will give you a cycle, no matter how you permutate (e.g. 1035 from P3 and 3136 from P4 - there can't be a cycle here).
I'd probably try to build a chain by starting with the elements from one list, one by one, and for each element, find the elements from the remaining lists that are valid successors. For those that you've found, continue trying to find the next chain element from the remaining lists. When you've built a chain with one number from every list, you just have to check if the last two digits of the last number match the first two digits of the first number.
Note when looking for successors, you again don't have to traverse the entire lists. If you're looking for a successor to 3015 from P5, for example, you can stop when you hit a number that's 1600 or larger.
If that's too slow still, you could transform the lists other than the first one to maps where the map key is the first two digits and the associated values are lists of numbers that start with those digits. Saves you from going through the lists from the start again and again.
I hope this helps a bit.
btw, I sense some repetition in your code.
you can unite your [p3, p4, p5, p6, p7, p8] functions into one function that will take the 3 from the p3 as a parameter etc.
to find what the pattern is, you can make all the functions in the form of
pX n = ... `div` 2