Flattening a binary tree in a specific manner - haskell
Consider the following definitions of binary and unary trees, a function flatten, which converts binary and unary trees to lists (e.g, flatten (Node (Leaf 10) 11 (Leaf 20)) is [10,11,20]) and a function, reverseflatten, which converts lists to binary trees (in the specific manner described here (Defining a function from lists to binary and unary trees) and illustrated in the picture below):
data Tree a = Leaf a | Node (Tree a) a (Tree a) | UNode a (Tree a) deriving (Show)
flatten :: Tree a -> [a]
flatten (Leaf x) = [x]
flatten (Node l x r) = flatten l ++ [x] ++ flatten r
flatten (UNode l x) = [l] ++ flatten x
reverseflatten :: [a] -> Tree a
reverseflatten [x] = (Leaf x)
reverseflatten [x,y] = UNode x (Leaf y)
reverseflatten [x,y,z] = Node (Leaf x) y (Leaf z)
reverseflatten (x:y:xs) = revflat2 (x:y:xs)
revflat2 :: [a] -> Tree a
revflat2 [x] = (Leaf x)
revflat2 [x,y] = UNode y (Leaf x)
revflat2 [x,y,z] = Node (Leaf x) y (Leaf z)
revflat2 (x:y:xs) = Node (Leaf x) y (revflat2 ([head $ tail xs] ++ [head xs] ++ tail (tail xs)))
reverseflatten [1..5] is Node (Leaf 1) 2 (Node (Leaf 4) 3 (Leaf 5), but (reverseflatten(flatten(reverseflatten [1..5]))) does not return the same as reverseflatten [1..5]. How could flatten be modified so that reverseflatten x: xs is the same as (reverseflatten(flatten(reverseflatten x:xs)))?
reverseflatten forms the series of trees in the picture below.
For example, reverseflatten [x,y,z] forms Tree 2 in the picture, reverseflatten [x,y,z, x'] forms Tree 3, reverseflatten [x,y,z, x', y'] forms Tree 4, reverseflatten [x,y,z, x', y', z'] forms Tree 5, reverseflatten [x,y,z, x', y', z', x''] forms Tree 6, etcetera.
What I want is that reverseflatten x: xs is the same as (reverseflatten(flatten(reverseflatten x:xs))). So I need to design flatten so it has this effect.
I have made the following attempt (where the case flatten Node l x r is supposed to divide into a case in which r is a leaf, and a case where it is not):
flatten :: Tree a -> [a]
flatten (Leaf x) = [x]
flatten (UNode l x) = [l] ++ flatten x
flatten (Node l x r)
| r == Leaf y = [l, x, r]
| otherwise = flatten (Node l x (revflat2 ([head $ tail r] ++ [head r] ++ tail (tail r)))
but this produces:
experiment.hs:585:1: error:
parse error (possibly incorrect indentation or mismatched brackets)
|
585 | flatten (UNode l x) = [l] ++ flatten x
| ^
I think that your problem is that the first node of the tree does not have the same pattern as the others, as in if you look at Tree1 it goes [x,y,z] , whereas Tree4 goes [x,y,[x',z,y']].
You can see that the ordering of the child nodes do not follow that of the first one, which is why some people noted it feels un-natural. To fix it you can either change your definition of reverseFlattening to one that has a constant pattern, which I assume you don't want, or change your flatten to take this weird pattern into account:
data Tree a = Leaf a | Node (Tree a) a (Tree a) | UNode a (Tree a) deriving (Show)
reverseFlatten :: [a] -> Tree a
reverseFlatten [x] = (Leaf x)
reverseFlatten [x,y] = UNode y (Leaf x)
reverseFlatten [x,y,z] = Node (Leaf x) y (Leaf z)
reverseFlatten (x:y:xs) = Node (Leaf x) y (reverseFlatten ((xs !! 1) : (head xs) : (drop 2 xs)))
flatten :: Tree a -> [a]
flatten (Leaf x) = [x]
flatten (UNode l (Leaf x)) = [l,x]
flatten (Node (Leaf l) x r) = l : x : flattenRest r
flattenRest :: Tree a -> [a]
flattenRest (Leaf x) = [x]
flattenRest (UNode l (Leaf x)) = [l,x]
flattenRest (Node (Leaf l) x r) = x : l : flattenRest r
Note that I extended the pattern matching for your UNode and the left Node as you know already it will be a left-sided tree so there's no need to call your function if you know already what the result will be.
Testable specification
First we can implement your specification reverseflatten (flatten (reverseflatten (x : xs))) = reverseflatten (x : xs) as a QuickCheck property.
We parameterize it by flatten and reverseflatten so it is easy to plug in different implementations.
We specialize the element type to Int because we have to tell QuickCheck what to generate at some point.
The type variable a really means Tree Int, but the generality will be useful later.
import Test.QuickCheck
prop_flat :: (Eq a, Show a) =>
(a -> [Int]) -> ([Int] -> a) -> (Int, [Int]) -> Property
prop_flat f rf (x0, xs0) =
(rf . f . rf) xs === rf xs
where
xs = x0 : xs0
-- Also remember to derive both Show and Eq on Tree.
We can check that it's a nontrivial property by applying it to the incorrect implementation.
ghci> quickCheck $ prop_flat flatten reverseflatten
*** Failed! Falsifiable (after 5 tests and 8 shrinks):
(0,[0,0,1,0])
Node (Leaf 0) 0 (Node (Leaf 0) 1 (Leaf 0)) /= Node (Leaf 0) 0 (Node (Leaf 1) 0 (Leaf 0))
Flatten, first take
Now the implementation of flatten needs to be split in two stages, like reverseflatten, because the root behaves differently from the other nodes:
at the root, Node (Leaf x) y (Leaf z) → [x, y, z],
but in the inner nodes, Node (Leaf x) y (Leaf z) → [y, x, z]
Also note that all the trees you've shown, and those that can actually be generated by reverseflatten lean to the right, so we really only know what to do on patterns Leaf x, UNode x (Leaf y) and Node (Leaf x) y r, but not other patterns like UNode x (Node ...) or Node (Node ...) y r. Hence, considering the whole domain of Trees, flatten1 is highly partial:
flatten1 :: Tree a -> [a]
flatten1 (Leaf x) = [x]
flatten1 (UNode x (Leaf y)) = [x, y]
flatten1 (Node (Leaf x) y r) = x : y : flatten1' r
flatten1' :: Tree a -> [a]
flatten1' (Leaf x) = [x]
flatten1' (UNode x (Leaf y)) = [x, y]
flatten1' (Node (Leaf y) x r) = x : y : flatten1' r
Partiality notwithstanding, QuickCheck agrees:
ghci> quickCheck $ prop_flat flatten1 reverseflatten
+++ OK, passed 100 tests.
Flatten, total version
A total function can be obtained by generalizing the patterns a bit, but as the test above shows, the specification does not cover these extra cases. Whenever we pattern match on a nested Leaf y, we instead just get the whole tree ys and flatten it. If it does turn out to be ys = Leaf y, then it will be flattened to a singleton list, so the original semantics are preserved.
flatten2 :: Tree a -> [a]
flatten2 (Leaf x) = [x]
flatten2 (UNode x ys) = x : flatten2 ys
flatten2 (Node xs y r) = flatten2 xs ++ y : flatten2' r
flatten2' :: Tree a -> [a]
flatten2' (Leaf x) = [x]
flatten2' (UNode x ys) = x : flatten2' ys
flatten2' (Node ys x r) = x : flatten2' ys ++ flatten2' r
Flatten, totally specified version
Rather than arbitrarily generalizing the function on the unspecified part of its domain, we can also restrict its domain to match exactly the specification. This leads to an alternative type definition: in all examples, UNode only has a leaf subtree, and similarly Node has only a leaf as the left subtree, so we unpack those leaves into the constructors.
data Tree' a = Leaf' a | UNode' a a | Node' a a (Tree' a)
deriving (Eq, Show)
The implementation of flatten' is a straightforward adaptation of flatten1:
flatten' :: Tree' a -> [a]
flatten' (Leaf' x) = [x]
flatten' (UNode' x y) = [x, y]
flatten' (Node' x y r) = x : y : f'' r
f'' :: Tree' a -> [a]
f'' (Leaf' x) = [x]
f'' (UNode' x y) = [x, y]
f'' (Node' x y r) = y : x : f'' r
reverseflatten' is similarly adapted from a refactored version of reverseflatten.
reverseflatten' :: [a] -> Tree' a
reverseflatten' (x : []) = Leaf' x
reverseflatten' (x : y : []) = UNode' x y
reverseflatten' (x : y : z : r) = Node' x y (rf'' z r)
rf'' :: a -> [a] -> Tree' a
rf'' x [] = Leaf' x
rf'' x (y : []) = UNode' x y
rf'' x (y : z : r) = Node' y x (rf'' z r)
QuickCheck validates:
ghci> quickCheck $ prop_flat flatten' reverseflatten'
+++ OK, passed 100 tests.
Let's hypothesize a slightly stronger property and just calculate without thinking, and see where it gets us. Namely, that stronger property will be that whenever xs is not empty, we have:
flatten (reverseflatten xs) = xs
From the definition of reverseflatten, there are four cases to consider. The first is this:
flatten (reverseflatten [x]) = [x]
flatten (Leaf x) = [x]
Next:
flatten (reverseflatten [x,y]) = [x,y]
flatten (UNode x (Leaf y)) = [x,y]
Then:
flatten (reverseflatten [x,y,z]) = [x,y,z]
flatten (Node (Leaf x) y (Leaf z)) = [x,y,z]
Finally:
flatten (reverseflatten (x:y:xs)) = x:y:xs
flatten (revflat2 (x:y:xs)) = x:y:xs
Because the previous patterns have captured the situations where xs matches [] or [_], we need only consider one case of revflat2, namely, the one where xs has at least two elements.
flatten (revflat2 (x:y:w:z:xs)) = x:y:w:z:xs
flatten (Node (Leaf x) y (revflat2 (z:w:xs))) = x:y:w:z:xs
Aha! For this to work, it would be nice to have a helper with a new property, namely:
flatten2 (revflat2 (z:w:xs)) = w:z:xs
(We'll actually use the names x and y instead of w and z, of course.)
Once again let us calculate without thinking. There are three cases for xs, namely [], [_], and longer. When xs is []:
flatten2 (revflat2 [x,y]) = [y,x]
flatten2 (UNode y (Leaf x)) = [y,x]
For [_]:
flatten2 (revflat2 [x,y,z]) = [y,x,z]
flatten2 (Node (Leaf x) y (Leaf z)) = [y,x,z]
And for longer:
flatten2 (revflat2 (x:y:w:z:xs)) = y:x:w:z:xs
flatten2 (Node (Leaf x) y (revflat2 (z:w:xs))) = y:x:w:z:xs
By induction hypothesis, we have flatten2 (revflat2 (z:w:xs)) = w:z:xs, so this last equation can become:
flatten2 (Node (Leaf x) y rest) = y:x:flatten2 rest
Now we can just take all the final lines of each of these cases and they make a program:
flatten (Leaf x) = [x]
flatten (UNode x (Leaf y)) = [x,y]
flatten (Node (Leaf x) y (Leaf z)) = [x,y,z]
flatten (Node (Leaf x) y rest) = x:y:flatten2 rest
flatten2 (UNode y (Leaf x)) = [y,x]
flatten2 (Node (Leaf x) y (Leaf z)) = [y,x,z]
flatten2 (Node (Leaf x) y rest) = y:x:flatten2 rest
Is this the best program? No! In particular, it's partial -- you have some free choices you can make about what flatten and flatten2 should do when the first tree argument to a Node or UNode is not a Leaf (but no matter what choice you make it will not affect the property you care about) and about what flatten2 should do with leaves. Likely if you make sane choices here, you can coalesce many of the patterns.
But what's nice about this process is that it's completely mechanical: you can take your property of interest, turn a crank, and get out a function with that property (or conflicting equations that tell you it's not possible and why). Only once you have something that works do you need to stare and think about what would make it prettier or better. Yay, equational reasoning!
Related
Return the Branch in a Data Tree Haskell
I am trying to return the branches in a Data Tree. Currently my code only returns the first branch. data DTree a = Leaf a | Branch a (DTree a) (DTree a) deriving (Show) get_b :: DTree Int -> [Int] get_branches (Branch x _ _) = [x] get_branches (Branch _ l r) = get_branches r ++ get_branches l Example output ghci > get_branches (Branch 2 (Leaf 3) (Branch 1 (Leaf 9) (Leaf 5))) [2]
Perhaps this is something youre looking for? get_branches :: DTree Int -> [Int] get_branches (Branch x l r) = [x] ++ get_branches r ++ get_branches l get_branches (Leaf x) = [x] There is no base case for your function. So use the pattern 'Leaf'. Additionally, the patterns (Branch x _ _) (Branch _ l r) are the same pattern, except with (Branch _ l r) you get the left and right branch.
Haskell will perform pattern matching from top to bottom. Since a Branch &hellip … … is matched by the first clause it will never trigger the second clause. Furthermore your program does not cover the Leaf case. If you want to construct a list of values in the inodes (the Branches), then we can work with: get_branches :: DTree a -> [a] get_branches (Leaf _) = [] get_branches (Branch x l r) = x : get_branches r ++ get_branches l here we first return the value of the branch, and then the values of the branches of the subtrees (first the left subtree and then the right subtree). For example with: get_branches :: DTree a -> [a] get_branches (Leaf _) = [] get_branches (Branch x l r) = get_branches r ++ x : get_branches l this will result in a lot of appending, which is linear in the size of the first list. We can prevent this by making calls where we pass a recursive call as tail, so: get_branches :: DTree a -> [a] get_branches = go [] where go tl (Leaf _) = tl go tl (Branch x l r) = go (x : go tl r) l
Haskell - Expressing the Depth First Traversal of a Rose Tree as an instance of unfold, deriving it algebraically
Suppose we have a Rose Tree defined, along with the corresponding fold over the datatype. data RTree a = Node a [RTree a] foldRTree :: (a -> [b] -> b) -> RTree a -> b foldRTree f (Node x xs) = f x (map (foldRTree f) xs) A recursive definition of a depth first traversal of such a structure would be: dft :: RTree a -> [a] dft (Node x xs) = x : concat (map dft xs) We can express dft as a fold over Rose Trees, and in particular we can derive such a fold algebraically. // Suppose dft = foldRTree f // Then foldRTree f (Node x xs) = f x (map (foldRTree f) xs) (definition of foldRTree) // But also foldRTree f (Node x xs) = dft (Node x xs) (by assumption) // = x : concat (map dft xs) (definition of dft) // So we deduce that f x (map (foldRTree f) xs) = x : concat (map dft xs) // Hence f x (map dft xs) = x : concat (map dft xs) (by assumption) // So we now see that f x y = x : concat y I suppose the reason we can do this is because foldRTree captures the general recursion structure over RTrees which brings me to my query about unfold. We define unfold as follows: unfold :: (a -> Bool) -> (a -> b) -> (a -> a) -> a -> [b] unfold n h t x | n x = [] | otherwise = h x : unfold n h t (t x) // Or Equivalently unfold' n h t = map h . takeWhile (not.n) . iterate t We can express the depth first traversal as an unfold as follows: dft (Node x xs) = x : unfold null h t xs where h ((Node a xs) : ys) = a t ((Node a xs) : ys) = xs ++ ys I am struggling to find a way to develop a way of algebraically calculating the functions n h t in the same way as cons. In particular there is a ingenious step in developing the unfold which is to realise that the final argument to unfold needs to be of type [RTree a] and not just RTree a. Therefore the argument posed to dft is not passed straight to the unfold and so we reach a hurdle with regards to reasoning about these two functions. I would be extremely grateful to anyone who could provide a mathematical way of reasoning about unfold in such a way to calculate the required functions n h, and t when expressing a recursive function (that is naturally a fold) as an unfold (perhaps using some laws linking fold and unfold?). A natural question would then be what methods we have to prove such a relation correct.
inductive step of proof by structural induction
I am given the following 2 versions of a tree-flattening program and i am asked to prove identical behaviour. flatten::Tree->[Int] flatten (Leaf z) =[z] F.1 flatten (Node x y) =concat (flatten x)(flatten y) F.2 flatten'::Tree->Int->[Int] flatten' (Leaf z) a =concat [z] a P.1 flatten' (Node x y) a =flatten' x (flatten' y a) P.2 concat->[a]->a->[a] concat [] a =a C.1 concat (h:t) a =h:concat t a C.2 Prove that: flatten' z a = concat (flatten z) a Base Case: LHS: flatten' (Leaf z) a = concat [z] a By P.1 RHS: concat (flatten z) a = concat (flatten (Leaf z)) a = concat [z] a By F.1 and C.1 LHS=RHS, hence base case holds Inductive Case: (Only possible thanks to the guy below who explained how induction on binary trees works!) Assume that: flatten' x a = concat (flatten x) a Ind. Hyp1 flatten' y a = concat (flatten y) a Ind. Hyp2 Show that: flatten'(Node x y) a = concat (flatten (Node x y)) a LHS: flatten' (Node x y) a = flatten' x (flatten' y a) By P.2 flatten' x (concat (flatten y) a) By Ind. Hyp2 concat (flatten x) (concat (flatten y) a) By Ind. Hyp1 RHS: concat (flatten (Node x y)) a = concat (concat (flatten x) (flatten y)) a By F.2 concat (flatten x) (concat (flatten y) a) By C.2 LHS = RHS, hence inductive step holds. End of proof.
When inducting on lists, your induction hypothesis is that the wanted property holds on the list tail, and you have to prove that it also holds on the whole list. On trees, it's only slightly different: your induction hypothesis is that the wanted property holds on both subtrees, and you have to prove that is also holds on the whole tree. Assume that: forall a, flatten' x a = concat (flatten x) a Ind. Hyp. 1 forall a, flatten' y a = concat (flatten y) a Ind. Hyp. 2 Show that: forall a, flatten'(Node x y) a = concat (flatten (Node x y)) a I think you can now guess how to proceed from here, so I won't spoil the fun. You might need to rely on some basic property of concat for some sub-step. Final note: in your base case, you mentioned C.1 as a justification -- are you sure you actually used that?
Join or merge function in haskell
Is there a function in Haskell to do the equivalent of an SQL join or an R merge ? Basically I have two list of tuples and would like to 'zip' them according to their key. I know there is only one or zero value for each key a = [(1, "hello"), (2, "world")] b = [(3, "foo"), (1, "bar")] And get something like [ (Just (1, "hello), Just (1, "bar)) , (Just (2, "world), Nothing) , (Nothing , Just (3, "foo")) ]
With ordered sets (lists) and Ord key key = fst fullOuterJoin xs [] = map (\x -> (Just x, Nothing)) xs fullOuterJoin [] ys = map (\y -> (Nothing, Just y)) ys fullOuterJoin xss#(x:xs) yss#(y:ys) = if key x == key y then (Just x, Just y): fullOuterJoin xs ys else if key x < key y then (Just x, Nothing): fullOuterJoin xs yss else (Nothing, Just y): fullOuterJoin xss ys (complexity is O(n+m) but if you must to sort then is O(n log n + m log m)) example setA = [(1, "hello"), (2, "world")] setB = [(1, "bar"), (3, "foo")] *Main> fullOuterJoin setA setB [(Just (1,"hello"),Just (1,"bar")),(Just (2,"world"),Nothing),(Nothing,Just (3, "foo"))] (obviously with sort support fullOuterJoin' xs ys = fullOuterJoin (sort xs) (sort ys) As #Franky say, you can avoid if, for example fullOuterJoin xs [] = [(Just x, Nothing) | x <- xs] fullOuterJoin [] ys = [(Nothing, Just y) | y <- ys] fullOuterJoin xss#(x:xs) yss#(y:ys) = case (compare `on` key) x y of EQ -> (Just x, Just y): fullOuterJoin xs ys LT -> (Just x, Nothing): fullOuterJoin xs yss GT -> (Nothing, Just y): fullOuterJoin xss ys
I can not think of any standard function doing this operation. I would convert the two lists into Data.Map.Maps and code the SQL-join myself. In this way, it looks doable with O(n log n) complexity, which is not too bad.
If you care about performance, this is not the answer you are looking for. No answer for a built-in function since you didn't give a type. It can be done by a simple list comprehension joinOnFst as bs = [(a,b) | a<-as, b<-bs, fst a == fst b] or with pattern matching and a different return type joinOnFst as bs = [(a1,a2,b2) | (a1,a2)<-as, (b1,b2)<-bs, a1==b1] More abstract, you can define listJoinBy :: (a -> b -> Bool) -> [a] -> [b] -> [(a,b)] listJoinBy comp as bs = [(a,b) | a<-as, b<-bs, comp a b] listJoin :: (Eq c) => (a -> c) -> (b -> c) -> [a] -> [b] -> [(a,b)] listJoin fa fb = listJoinBy (\a b -> fa a == fb b) I bet the last line can be made point-free or at least the lambda can be eliminated.
You're asking if there's a way to something like a SQL join in Haskell. Rosetta code has an example in Haskell of how to do a hash join, which is the algorithm lots of RDBMS's use for JOINs, one of which is presented as cleaner (though it is slower): a cleaner and more functional solution would be to use Data.Map (based on binary trees): import qualified Data.Map as M import Data.List import Data.Maybe import Control.Applicative mapJoin xs fx ys fy = joined where yMap = foldl' f M.empty ys f m y = M.insertWith (++) (fy y) [y] m joined = concat . mapMaybe (\x -> map (x,) <$> M.lookup (fx x) yMap) $ xs main = mapM_ print $ mapJoin [(1, "Jonah"), (2, "Alan"), (3, "Glory"), (4, "Popeye")] snd [("Jonah", "Whales"), ("Jonah", "Spiders"), ("Alan", "Ghosts"), ("Alan", "Zombies"), ("Glory", "Buffy")] fst
What you asked is basically ordzip a#(x:t) b#(y:r) = case compare x y of LT -> (Just x, Nothing) : ordzip t b EQ -> (Just x, Just y) : ordzip t r GT -> (Nothing, Just y) : ordzip a r ordzip a [] = [(Just x, Nothing) | x <- a] ordzip [] b = [(Nothing, Just y) | y <- b] With it, we can further define e.g. import Control.Applicative (<|>) diff xs ys = [x | (Just x, Nothing) <- ordzip xs ys] -- set difference meet xs ys = [y | (Just _, Just y) <- ordzip xs ys] -- intersection union xs ys = [z | (u,v) <- ordzip xs ys, let Just z = u <|> v] or have few variations concerning the access to keys or handling of duplicates etc. (like defining ordzipBy k a#(x:t) b#(y:r) = case compare (k x) (k y) of ...). But this is better represented with Data.These.These type to explicate the fact that (Nothing, Nothing) can never happen: import Data.These ordzip a#(x:t) b#(y:r) = case compare x y of LT -> This x : ordzip t b GT -> That y : ordzip a r _ -> These x y : ordzip t r diff xs ys = catThis $ ordzip xs ys meet xs ys = map snd . catThese $ ordzip xs ys -- or map fst, or id union xs ys = map (mergeThese const) $ ordzip xs ys Of course the input lists are to be sorted by the key beforehand.
Haskell Tree to List - preorder traversal
Given the following tree structure in Haskell: data Tree = Leaf Int | Node Int Tree Tree deriving Show How can I get Haskell to return a list of the data in pre-order? e.g. given a tree: Node 1 (Leaf 2) (Leaf 3) return something like: preorder = [1,2,3]
You could aim to a more general solution and make your data type an instance of Foldable. There is a very similar example at hackage, but that implements a post-order visit. If you want to support pre-order visits you will have to write something like this: import qualified Data.Foldable as F data Tree a = Leaf a | Node a (Tree a) (Tree a) deriving Show instance F.Foldable Tree where foldr f z (Leaf x) = f x z foldr f z (Node k l r) = f k (F.foldr f (F.foldr f z r) l) With this, you'll be able to use every function that works on Foldable types, like elem, foldr, foldr, sum, minimum, maximum and such (see here for reference). In particular, the list you are searching for can be obtain with toList. Here are some examples of what you could write by having that instance declaration: *Main> let t = Node 1 (Node 2 (Leaf 3) (Leaf 4)) (Leaf 5) *Main> F.toList t [1,2,3,4,5] *Main> F.foldl (\a x -> a ++ [x]) [] t [1,2,3,4,5] *Main> F.foldr (\x a -> a ++ [x]) [] t [5,4,3,2,1] *Main> F.sum t 15 *Main> F.elem 3 t True *Main> F.elem 12 t False
Use pattern matching preorder (Leaf n) = [n] preorder (Node n a b) = n:(preorder a) ++ (preorder b)
Ok, sorry about the late reply, but I got this working as follows: preorder(Leaf n) = [n] preorder(Node n treeL treeR) = [n] ++ preorder treeL ++ preorder treeR'code' This however does not work for me still preorder (Leaf n) = [n] preorder (Node n a b) = n:(preorder a) ++ (preorder b)