I'm studying for my exam and I can't figure out how to answer this question.
Make a function that returns a linked list of the post traversal of a binary tree. You cannot use any containers to store your data before hand and it must be recursive.
So I can't take the post traversal, put it in a list and then iterate through it to make a linked list.
There was another question that said to do the same thing but for a inorder traversal and this was the solution.
There are two solutions. One that I don't understand and a clear version of that one
THIS IS THE MAIN SOLUTION
def inorder(root: BTNode) -> LLNode:
"""Return the first node in a linked list that contains every value from the
binary tree rooted at root, listed according to an inorder traversal.
>>> b = BTNode(1, BTNode(2), BTNode(3))
>>> repr(inorder(b))
'LLNode(2, LLNode(1, LLNode(3)))'
>>> b2 = BTNode(4, BTNode(5))
>>> b3 = BTNode(7, b, b2)
>>> str(inorder(b3))
'2 -> 1 -> 3 -> 7 -> 5 -> 4'
>>> # from the handout...
>>> left = BTNode('B', None, BTNode('D', BTNode('G')))
>>> right = BTNode('C', BTNode('E'), BTNode('F'))
>>> root = BTNode('A', left, right)
>>> str(inorder(root))
'B -> G -> D -> A -> E -> C -> F'
"""
return _inorder(root)[0]
def _inorder(root: BTNode) -> (LLNode, LLNode):
"""Return the first and last nodes in a linked list that contains every
value from the binary tree rooted at root, listed according to an inorder
traversal.
"""
if root:
head_left, tail_left = _inorder(root.left)
head_right, tail_right = _inorder(root.right)
node_root = LLNode(root.item, head_right)
if tail_left:
tail_left.link = node_root
return head_left or node_root, tail_right or node_root
else:
return None, None
CLEAR SOLUTION
def inorder(root: BTNode) -> LLNode:
"""Return the first node in a linked list that contains every value from the
binary tree rooted at root, listed according to an inorder traversal.
>>> b = BTNode(1, BTNode(2), BTNode(3))
>>> repr(inorder(b))
'LLNode(2, LLNode(1, LLNode(3)))'
>>> b2 = BTNode(4, BTNode(5))
>>> b3 = BTNode(7, b, b2)
>>> str(inorder(b3))
'2 -> 1 -> 3 -> 7 -> 5 -> 4'
>>> # from the handout...
>>> left = BTNode('B', None, BTNode('D', BTNode('G')))
>>> right = BTNode('C', BTNode('E'), BTNode('F'))
>>> root = BTNode('A', left, right)
>>> str(inorder(root))
'B -> G -> D -> A -> E -> C -> F'
"""
return _inorder(root)[0] # what must this first item represent?
def _inorder(root: BTNode) -> (LLNode, LLNode): # what are these 1st and 2nd things?
"""Return the first and last nodes in a linked list that contains every
value from the binary tree rooted at root, listed according to an inorder
traversal.
>>> left = BTNode('B', None, BTNode('D', BTNode('G')))
>>> right = BTNode('C', BTNode('E'), BTNode('F'))
>>> root = BTNode('A', left, right)
>>> str(inorder(root))
'B -> G -> D -> A -> E -> C -> F'
"""
if not root:
return None, None
else:
# Start off by making a new node of our item, with None for a link
# Obviously we will need to replace that None if we have a right branch
new_node = LLNode(root.item)
# Recursive call on right branch gives us its head and tail
right_head, right_tail = _inorder(root.right)
# The link on our new node should be the right head, even if it's None
new_node.link = right_head
# Ultimately the tail for this whole node will be the rightmost tail
# If there is no right side, though, this node is the rightmost tail
if not right_tail:
right_tail = new_node
# Recursive call on left branch gives us its head and tail
left_head, left_tail = _inorder(root.left)
# If there is a left tail, we should string our current node to the end
if left_tail:
left_tail.link = new_node
# Ultimately the head for this whole node will be the leftmost head
# If there is no left head, though, this node is the leftmost head
if not left_head:
left_head = new_node
# Return the leftmost head and the rightmost tail
return left_head, right_tail
I am not sure what keeps you from understanding the main solution. The comment explains it very well. In any case, the recursive call to _inorder(root.left) flattens the left subtree, and returns the head and tail of the resulting list. Same way, the recursive call to _inorder(root.right) flattens the right subtree. Now you have two lists,
head_left-> ... ->tail_left
head_right-> ... ->tail_right
stitch them with the root,
head_left-> ... ->tail_left->root->head_right-> ... ->tail_right
and return the resulting list
head_left-> ... ->tail_right
To achieve the postorder, stitch them as in
head_left-> ... ->tail_left->head_right-> ... ->tail_right->root
and return
head_left-> ... ->root
Related
I have the following rose tree in haskell:
data R = B [R] -- B for Branch
I am trying to create the following function :
append :: R -> [R] -> R
This functions is supposed to take as input a rose tree (R) and a list of a rose trees [R] (assuming that number of leaves of R is equal to the number of elements from the list so each leaf gets a new branch) and add each element from [R] to the R and then return the final rose trees.
An example would be
append B[B[B[],B[]],B[],B[]] [ B[B[],B[]], B[], B[B[]], B[] ] =
B[B[B[B[B[],B[]]],B[B[]]],B[B[B[]]],B[B[]]]
The list in this case consist of 4 elements specifically :
B[B[],B[]]
B[]
B[B[]]
B[]
And each one got inserted accordingly
I managed to partially implement the solution:
append (B []) (l:list) = l
append (B [x]) list = append x list
However these steps just add the first element from the list to each leaf! So how could I implement this functionality so I can move around the list?
I am having a hard time understanding the tree_traverse function and what it does, could someone please explain.
(Peek and pop is just from a stack implementation which I made.)
type 'a tree = Leaf | Branch of ('a tree * 'a * 'a tree);;
let rec tree_traverse (t,mem,prim,seco) = match t with
| Leaf ->
if is_empty mem
then []
else tree_traverse (peek mem, pop mem, prim, seco)
| Branch (l,nd,r) ->
let mem1 = add (prim(l,r),mem) in
let mem2 = add (seco(l,r), mem1) in
nd :: tree_traverse (peek mem2, pop mem2, prim, seco)
where an example of a tree is
let t = Branch (Branch(Branch(Leaf,1,Leaf), 2, Leaf), 3,
Branch (Branch(Leaf,5,Leaf), 6, Branch(Leaf,7,Leaf)))
This function implements some sort of the worklist algorithm, it returns a list of nodes in some order that depends on the implementation of prim and seco functions, as well as add and pop.
Neither prim nor seco parameter is changed during the recursion, so the could be removed from the list of parameters. If we will assume the following implementations
let add (x,xs) = x :: xs
let pop (x::xs) = xs
let peek (x::xs) = x
let prim (x,y) = x
let seco (x,y) = y
let is_empty = function [] -> true | _ -> false
then the tree_traverse function will return the list of nodes in the depth-first order.
Given your example and fixing the implementation to the specified above functions, we can now follow the execution of the function:
tree_traverse Branch (Branch(Branch(Leaf,1,Leaf), 2, Leaf), 3,
Branch (Branch(Leaf,5,Leaf), 6, Branch(Leaf,7,Leaf)))
doesn't match with the Leaf case so we go to the second case and get it deconstructed as
| Branch (l,nd,r)) ->
(* l is bound to Branch (Branch(Leaf,1,Leaf), 2, Leaf) *)
(* nd is bound to 3 *)
(* r is bound to Branch (Branch(Leaf,5,Leaf), 6, Branch(Leaf,7,Leaf)) *)
let mem1 = add (prim(l,r),mem) in
let mem2 = add (seco(l,r), mem1) in
nd :: tree_traverse (peek mem2, pop mem2, prim, seco)
we push the left sub-branch l to the first stack mem1, and push the left and right subbranches to the stack mem2. Then we prepend 3 to the result and recurse with into the top of our stack mem2 while dropping it.
In the next step, we are matching on the top of our second stack, which contains the right branch, namely Branch (Branch(Leaf,5,Leaf), 6, Branch(Leaf,7,Leaf)), we land again to the second case, with
Branch(Leaf,5,Leaf) being bound to the l variable, and Branch(Leaf,7,Leaf) to r. We add 6 to the result, and push l then push and immediately pop r and recurse into it.
On the third step of recursion we are called with Branch(Leaf,7,Leaf), we add 7 to our result, and push left and right Leaf to our stack.
On the fourth step, we peek the Leaf node, and finally get into the first case, where we look into the stack, and if it is not empty, then we recurse into the top. In our case the stack contains our sibling left Leaf, then the left sibling of the parent node, etc.
You can do the same using the OCaml toplevel, e.g.,
#trace tree_traverse;;
tree_traverse (t,[],prim,seco);;
Use the definitions of the helper function, as I provided above.
I have the following code to do an inorder traversal of a Binary Tree:
data BinaryTree a =
Node a (BinaryTree a) (BinaryTree a)
| Leaf
deriving (Show)
inorder :: (a -> b -> b) -> b -> BinaryTree a -> b
inorder f acc tree = go tree acc
where go Leaf z = z
go (Node v l r) z = (go r . f v . go l) z
Using the inorder function above I'd like to get the kth element without having to traverse the entire list.
The traversal is a little like a fold given that you pass it a function and a starting value. I was thinking that I could solve it by passing k as the starting value, and a function that'll decrement k until it reaches 0 and at that point returns the value inside the current node.
The problem I have is that I'm not quite sure how to break out of the recursion of inorder traversal short of modifying the whole function, but I feel like having to modify the higher order function ruins the point of using a higher order function in the first place.
Is there a way to break after k iterations?
I observe that the results of the recursive call to go on the left and right subtrees are not available to f; hence no matter what f does, it cannot choose to ignore the results of recursive calls. Therefore I believe that inorder as written will always walk over the entire tree. (edit: On review, this statement may be a bit strong; it seems f may have a chance to ignore left subtrees. But the point basically stands; there is no reason to elevate left subtrees over right subtrees in this way.)
A better choice is to give the recursive calls to f. For example:
anyOldOrder :: (a -> b -> b -> b) -> b -> BinaryTree a -> b
anyOldOrder f z = go where
go Leaf = z
go (Node v l r) = f v (go l) (go r)
Now when we write
flatten = anyOldOrder (\v ls rs -> ls ++ [v] ++ rs) []
we will find that flatten is sufficiently lazy:
> take 3 (flatten (Node 'c' (Node 'b' (Node 'a' Leaf Leaf) Leaf) undefined))
"abc"
(The undefined is used to provide evidence that this part of the tree is never inspected during the traversal.) Hence we may write
findK k = take 1 . reverse . take k . flatten
which will correctly short-circuit. You can make flatten slightly more efficient with the standard difference list technique:
flatten' t = anyOldOrder (\v l r -> l . (v:) . r) id t []
Just for fun, I also want to show how to implement this function without using an accumulator list. Instead, we will produce a stateful computation which walks over the "interesting" part of the tree, stopping when it reaches the kth element. The stateful computation looks like this:
import Control.Applicative
import Control.Monad.State
import Control.Monad.Trans.Maybe
kthElem k v l r = l <|> do
i <- get
if i == k
then return v
else put (i+1) >> r
Looks pretty simple, hey? Now our findK function will farm out to kthElem, then do some newtype unwrapping:
findK' k = (`evalState` 1) . runMaybeT . anyOldOrder (kthElem 3) empty
We can verify that it is still as lazy as desired:
> findK' 3 $ Node 'c' (Node 'b' (Node 'a' Leaf Leaf) Leaf) undefined
Just 'c'
There are (at least?) two important generalizations of the notion of folding a list. The first, more powerful, notion is that of a catamorphism. The anyOldOrder of Daniel Wagner's answer follows this pattern.
But for your particular problem, the catamorphism notion is a bit more power than you need. The second, weaker, notion is that of a Foldable container. Foldable expresses the idea of a container whose elements can all be mashed together using the operation of an arbitrary Monoid. Here's a cute trick:
{-# LANGUAGE DeriveFoldable #-}
-- Note that for this trick only I've
-- switched the order of the Node fields.
data BinaryTree a =
Node (BinaryTree a) a (BinaryTree a)
| Leaf
deriving (Show, Foldable)
index :: [a] -> Int -> Maybe a
[] `index` _ = Nothing
(x : _) `index` 0 = Just x
(_ : xs) `index` i = xs `index` (i - 1)
(!?) :: Foldable f => Int -> f a -> Maybe a
xs !? i = toList xs `index` i
Then you can just use !? to index into your tree!
That trick is cute, and in fact deriving Foldable is a tremendous convenience, but it won't help you understand anything. I'll start by showing how you can define treeToList fairly directly and efficiently, without using Foldable.
treeToList :: BinaryTree a -> [a]
treeToList t = treeToListThen t []
The magic is in the treeToListThen function. treeToListThen t more converts t to a list and appends the list more to the end of the result. This slight generalization turns out to be all that's required to make conversion to a list efficient.
treeToListThen :: BinaryTree a -> [a] -> [a]
treeToListThen Leaf more = more
treeToListThen (Node v l r) more =
treeToListThen l $ v : treeToListThen r more
Instead of producing an inorder traversal of the left subtree and then appending everything else, we tell the left traversal what to stick on the end when it's done! This avoids the potentially serious inefficiency of repeated list concatenation that can turn things O(n^2) in bad cases.
Getting back to the Foldable notion, turning things into lists is a special case of foldr:
toList = foldr (:) []
So how can we implement foldr for trees? It ends up being somewhat similar to what we did with toList:
foldrTree :: (a -> b -> b) -> b -> BinaryTree a -> b
foldrTree _ n Leaf = n
foldrTree c n (Node v l r) = foldrTree c rest l
where
rest = v `c` foldrTree c n r
That is, when we go down the left side, we tell it that when it's done, it should deal with the current node and its right child.
Now foldr isn't quite the most fundamental operation of Foldable; that is actually
foldMap :: (Foldable f, Monoid m)
=> (a -> m) -> f a -> m
It is possible to implement foldr using foldMap, in a somewhat tricky fashion using a peculiar Monoid. I don't want to overload you with details of that right now, unless you ask (but you should look at the default definition of foldr in Data.Foldable). Instead, I'll show how foldMap can be defined using Daniel Wagner's anyOldOrder:
instance Foldable BinaryTree where
foldMap f = anyOldOrder bin mempty where
bin lres v rres = lres <> f v <> rres
I am reading this paper by Chris Okasaki; titled "Breadth-First Numbering: Lessons from a Small Exercise in Algorithm Design".
A question is - how is the magic happening in the algorithm? There are some figures (e.g. figure 7 titled "threading the output of one level into the input of next level")
Unfortunately, maybe it's only me, but that figure has completely baffled me. I don't understand how the threading happens at all?
Breadth first traversal means traversing levels of a tree one by one. So let's assume we already know what are the numbers at the beginning of each level - the number of traversed elements so far before each level. For the simple example in the paper
import Data.Monoid
data Tree a = Tree (Tree a) a (Tree a)
| Empty
deriving (Show)
example :: Tree Char
example = Tree (Tree Empty 'b' (Tree Empty 'c' Empty)) 'a' (Tree Empty 'd' Empty)
the sizes would be 0, 1, 3, 4. Knowing this, we can thread such a list of sizes through a give tree (sub-tree) left-to-right: We advance the first element of the list by one for the node, and thread the tail of the list first through the left and then through the right subtree (see thread below).
After doing so, we'll get again the same list of sizes, only shifted by one - now we have the total number of elements after each level. So the trick is: Assume we have such a list, use it for the computation, and then feed the output as the input - tie the knot.
A sample implementation:
tagBfs :: (Monoid m) => (a -> m) -> Tree a -> Tree m
tagBfs f t = let (ms, r) = thread (mempty : ms) t
in r
where
thread ms Empty = (ms, Empty)
thread (m : ms) (Tree l x r) =
let (ms1, l') = thread ms l
(ms2, r') = thread ms1 r
in ((m <> f x) : ms2, Tree l' m r')
generalized to Monoid (for numbering you'd give const $ Sum 1 as the function).
One way to view tree numbering is in terms of a traversal. Specifically, we want to traverse the tree in breadth-first order using State to count up. The necessary Traversable instance looks something like this. Note that you'd probably actually want to define this instance for a newtype like BFTree, but I'm just using the raw Tree type for simplicity. This code is strongly inspired by ideas in Cirdec's monadic rose tree unfolding code, but the situation here seems to be substantially simpler. Hopefully I haven't missed something horrible.
{-# LANGUAGE DeriveFunctor,
GeneralizedNewtypeDeriving,
LambdaCase #-}
{-# OPTIONS_GHC -Wall #-}
module BFT where
import Control.Applicative
import Data.Foldable
import Data.Traversable
import Prelude hiding (foldr)
data Tree a = Tree (Tree a) a (Tree a)
| Empty
deriving (Show, Functor)
newtype Forest a = Forest {getForest :: [Tree a]}
deriving (Functor)
instance Foldable Forest where
foldMap = foldMapDefault
-- Given a forest, produce the forest consisting
-- of the children of the root nodes of non-empty
-- trees.
children :: Forest a -> Forest a
children (Forest xs) = Forest $ foldr go [] xs
where
go Empty c = c
go (Tree l _a r) c = l : r : c
-- Given a forest, produce a list of the root nodes
-- of the elements, with `Nothing` values in place of
-- empty trees.
parents :: Forest a -> [Maybe a]
parents (Forest xs) = foldr go [] xs
where
go Empty c = Nothing : c
go (Tree _l a _r) c = Just a : c
-- Given a list of values (mixed with blanks) and
-- a list of trees, attach the values to pairs of
-- trees to build trees; turn the blanks into `Empty`
-- trees.
zipForest :: [Maybe a] -> Forest a -> [Tree a]
zipForest [] _ts = []
zipForest (Nothing : ps) ts = Empty : zipForest ps ts
zipForest (Just p : ps) (Forest ~(t1 : ~(t2 : ts'))) =
Tree t1 p t2 : zipForest ps (Forest ts')
instance Traversable Forest where
-- Traversing an empty container always gets you
-- an empty one.
traverse _f (Forest []) = pure (Forest [])
-- First, traverse the parents. The `traverse.traverse`
-- gets us into the `Maybe`s. Then traverse the
-- children. Finally, zip them together, and turn the
-- result into a `Forest`. If the `Applicative` in play
-- is lazy enough, like lazy `State`, I believe
-- we avoid the double traversal Okasaki mentions as
-- a problem for strict implementations.
traverse f xs = (Forest .) . zipForest <$>
(traverse.traverse) f (parents xs) <*>
traverse f (children xs)
instance Foldable Tree where
foldMap = foldMapDefault
instance Traversable Tree where
traverse f t =
(\case {(Forest [r]) -> r;
_ -> error "Whoops!"}) <$>
traverse f (Forest [t])
Now we can write code to pair up each element of the tree with its breadth-first number like this:
import Control.Monad.Trans.State.Lazy
numberTree :: Tree a -> Tree (Int, a)
numberTree tr = flip evalState 1 $ for tr $ \x ->
do
v <- get
put $! (v+1)
return (v,x)
Ok, I have written a binary search tree in OCaml.
type 'a bstree =
|Node of 'a * 'a bstree * 'a bstree
|Leaf
let rec insert x = function
|Leaf -> Node (x, Leaf, Leaf)
|Node (y, left, right) as node ->
if x < y then
Node (y, insert x left, right)
else if x > y then
Node (y, left, insert x right)
else
node
I guess the above code does not have problems.
When using it, I write
let root = insert 4 Leaf
let root = insert 5 root
...
Is this the correct way to use/insert to the tree?
I mean, I guess I shouldn't declare the root and every time I again change the variable root's value, right?
If so, how can I always keep a root and can insert a value into the tree at any time?
This looks like good functional code for inserting into a tree. It doesn't mutate the tree during insertion, but instead it creates a new tree containing the value. The basic idea of immutable data is that you don't "keep" things. You calculate values and pass them along to new functions. For example, here's a function that creates a tree from a list:
let tree_of_list l = List.fold_right insert l Leaf
It works by passing the current tree along to each new call to insert.
It's worth learning to think this way, as many of the benefits of FP derive from the use of immutable data. However, OCaml is a mixed-paradigm language. If you want to, you can use a reference (or mutable record field) to "keep" a tree as it changes value, just as in ordinary imperative programming.
Edit:
You might think the following session shows a modification of a variable x:
# let x = 2;;
val x : int = 2
# let x = 3;;
val x : int = 3
#
However, the way to look at this is that these are two different values that happen to both be named x. Because the names are the same, the old value of x is hidden. But if you had another way to access the old value, it would still be there. Maybe the following will show how things work:
# let x = 2;;
val x : int = 2
# let f () = x + 5;;
val f : unit -> int = <fun>
# f ();;
- : int = 7
# let x = 8;;
val x : int = 8
# f ();;
- : int = 7
#
Creating a new thing named x with the value 8 doesn't affect what f does. It's still using the same old x that existed when it was defined.
Edit 2:
Removing a value from a tree immutably is analogous to adding a value. I.e., you don't actually modify an existing tree. You create a new tree without the value that you don't want. Just as inserting doesn't copy the whole tree (it re-uses large parts of the previous tree), so deleting won't copy the whole tree either. Any parts of the tree that aren't changed can be re-used in the new tree.
Edit 3
Here's some code to remove a value from a tree. It uses a helper function that adjoins two trees that are known to be disjoint (furthermore all values in a are less than all values in b):
let rec adjoin a b =
match a, b with
| Leaf, _ -> b
| _, Leaf -> a
| Node (v, al, ar), _ -> Node (v, al, adjoin ar b)
let rec delete x = function
| Leaf -> Leaf
| Node (v, l, r) ->
if x = v then adjoin l r
else if x < v then Node (v, delete x l, r)
else Node (v, l, delete x r)
(Hope I didn't just spoil your homework!)