Difference between revisions of "99 questions/54A to 60"

From HaskellWiki
Jump to navigation Jump to search
m (new URL)
m
 
(12 intermediate revisions by 7 users not shown)
Line 3: Line 3:
 
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [https://prof.ti.bfh.ch/hew1/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems].
 
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [https://prof.ti.bfh.ch/hew1/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems].
   
  +
<h2 style="border:none">Binary trees</h2>
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields.
 
   
  +
A binary tree is either empty or it is composed of a root element and two successors, which are binary trees themselves. In Haskell, we can characterize binary trees with a datatype definition:
== Binary trees ==
 
   
  +
<haskell>
A binary tree is either empty or it is composed of a root element and two successors, which are binary trees themselves.
 
  +
data Tree a = Empty | Branch a (Tree a) (Tree a)
  +
deriving (Show, Eq)
  +
</haskell>
   
  +
This says that a <code>Tree</code> of type <code>a</code> consists of either an <code>Empty</code> node, or a <code>Branch</code> containing one value of type <code>a</code> with exactly two subtrees of type <code>a</code>.
https://prof.ti.bfh.ch/hew1/informatik3/prolog/p-99/p67.gif
 
   
  +
Given this definition, the tree in the diagram above would be represented as:
== Problem 54A ==
 
   
  +
<haskell>
(*) Check whether a given term represents a binary tree
 
  +
tree1 = Branch 'a' (Branch 'b' (Branch 'd' Empty Empty)
  +
(Branch 'e' Empty Empty))
  +
(Branch 'c' Empty
  +
(Branch 'f' (Branch 'g' Empty Empty)
  +
Empty))
  +
</haskell>
   
  +
Since a "leaf" node is a branch with two empty subtrees, it can be useful to define a shorthand function:
In Prolog or Lisp, one writes a predicate to do this.
 
   
Example in Lisp:
 
<pre>
 
* (istree (a (b nil nil) nil))
 
T
 
* (istree (a (b nil nil)))
 
NIL
 
</pre>
 
 
In Haskell, we characterize binary trees with a datatype definition:
 
 
<haskell>
 
<haskell>
data Tree a = Empty | Branch a (Tree a) (Tree a)
+
leaf x = Branch x Empty Empty
deriving (Show, Eq)
 
 
</haskell>
 
</haskell>
  +
The above tree is represented as:
 
  +
Then the tree diagram above could be expressed more simply as:
  +
 
<haskell>
 
<haskell>
tree1 = Branch 'a' (Branch 'b' (Branch 'd' Empty Empty)
+
tree1' = Branch 'a' (Branch 'b' (leaf 'd')
(Branch 'e' Empty Empty))
+
(leaf 'e'))
(Branch 'c' Empty
+
(Branch 'c' Empty
(Branch 'f' (Branch 'g' Empty Empty)
+
(Branch 'f' (leaf 'g')
Empty)))
+
Empty)))
 
</haskell>
 
</haskell>
  +
 
Other examples of binary trees:
 
Other examples of binary trees:
  +
 
<haskell>
 
<haskell>
tree2 = Branch 'a' Empty Empty -- a binary tree consisting of a root node only
+
-- A binary tree consisting of a root node only
  +
tree2 = Branch 'a' Empty Empty
   
tree3 = nil -- an empty binary tree
+
-- An empty binary tree
  +
tree3 = Empty
   
  +
-- A tree of integers
 
tree4 = Branch 1 (Branch 2 Empty (Branch 4 Empty Empty))
 
tree4 = Branch 1 (Branch 2 Empty (Branch 4 Empty Empty))
 
(Branch 2 Empty Empty)
 
(Branch 2 Empty Empty)
 
</haskell>
 
</haskell>
The type system ensures that all terms of type <hask>Tree a</hask>
 
are binary trees: it is just not possible to construct an invalid tree
 
with this type. Hence, it is redundant to introduce a predicate to
 
check this property: it would always return <hask>True</hask>.
 
   
== Problem 55 ==
 
   
  +
== Problem 54A ==
(**) Construct completely balanced binary trees
 
  +
<div style="border-bottom:1px solid #eee">(*) Check whether a given term represents a binary tree. <span style="float:right"><small>(no solution needed)</small></span>
  +
</div>
  +
&nbsp;<br>
  +
  +
In Prolog or Lisp, one writes a predicate to do this.
  +
  +
Example in Lisp:
  +
  +
<pre>
  +
* (istree (a (b nil nil) nil))
  +
T
  +
* (istree (a (b nil nil)))
  +
NIL
  +
</pre>
  +
  +
Note: Haskell's type system ensures that all terms of type <code>Tree a</code> are binary trees: it is just not possible to construct an invalid tree with this type. Hence, it is redundant to introduce a predicate to check this property: it would always return <code>True</code>.
  +
  +
  +
== Problem 55 ==
  +
<div style="border-bottom:1px solid #eee">(**) Construct completely balanced binary trees. <span style="float:right"><small>[[99 questions/Solutions/55|Solutions]]</small></span>
  +
</div>
  +
&nbsp;<br>
   
 
In a completely balanced binary tree, the following property holds for every node: The number of nodes in its left subtree and the number of nodes in its right subtree are almost equal, which means their difference is not greater than one.
 
In a completely balanced binary tree, the following property holds for every node: The number of nodes in its left subtree and the number of nodes in its right subtree are almost equal, which means their difference is not greater than one.
Line 61: Line 84:
   
 
Example:
 
Example:
  +
 
<pre>
 
<pre>
 
* cbal-tree(4,T).
 
* cbal-tree(4,T).
Line 69: Line 93:
   
 
Example in Haskell, whitespace and "comment diagrams" added for clarity and exposition:
 
Example in Haskell, whitespace and "comment diagrams" added for clarity and exposition:
  +
<pre>
 
  +
<haskell>
*Main> cbalTree 4
 
  +
λ> cbalTree 4
 
[
 
[
 
-- permutation 1
 
-- permutation 1
Line 112: Line 137:
 
(Branch 'x' Empty Empty)
 
(Branch 'x' Empty Empty)
 
]
 
]
</pre>
 
 
Solution:
 
<haskell>
 
cbalTree 0 = [Empty]
 
cbalTree n = [Branch 'x' l r | i <- [q .. q + r], l <- cbalTree i, r <- cbalTree (n - i - 1)]
 
where (q, r) = quotRem (n-1) 2
 
 
</haskell>
 
</haskell>
   
Here we use the list monad to enumerate all the trees, in a style that is more natural than standard backtracking.
 
 
 
 
== Problem 56 ==
 
== Problem 56 ==
  +
<div style="border-bottom:1px solid #eee">(**) Symmetric binary trees. <span style="float:right"><small>[[99 questions/Solutions/56|Solutions]]</small></span>
 
  +
</div>
(**) Symmetric binary trees
 
  +
&nbsp;<br>
   
 
Let us call a binary tree symmetric if you can draw a vertical line through the root node and then the right subtree is the mirror image of the left subtree. Write a predicate symmetric/1 to check whether a given binary tree is symmetric. Hint: Write a predicate mirror/2 first to check whether one tree is the mirror image of another. We are only interested in the structure, not in the contents of the nodes.
 
Let us call a binary tree symmetric if you can draw a vertical line through the root node and then the right subtree is the mirror image of the left subtree. Write a predicate symmetric/1 to check whether a given binary tree is symmetric. Hint: Write a predicate mirror/2 first to check whether one tree is the mirror image of another. We are only interested in the structure, not in the contents of the nodes.
   
 
Example in Haskell:
 
Example in Haskell:
  +
<pre>
 
  +
<haskell>
*Main> symmetric (Branch 'x' (Branch 'x' Empty Empty) Empty)
 
  +
λ> symmetric (Branch 'x' (Branch 'x' Empty Empty) Empty)
 
False
 
False
*Main> symmetric (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty))
+
λ> symmetric (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty))
 
True
 
True
</pre>
+
</haskell>
   
Solution:
 
<haskell>
 
mirror Empty Empty = True
 
mirror (Branch _ a b) (Branch _ x y) = mirror a y && mirror b x
 
mirror _ _ = False
 
 
symmetric Empty = True
 
symmetric (Branch _ l r) = mirror l r
 
</haskell>
 
 
 
 
== Problem 57 ==
 
== Problem 57 ==
  +
<div style="border-bottom:1px solid #eee">(**) Binary search trees. <span style="float:right"><small>[[99 questions/Solutions/57|Solutions]]</small></span>
 
  +
</div>
(**) Binary search trees (dictionaries)
 
  +
&nbsp;<br>
   
 
Use the predicate add/3, developed in chapter 4 of the course, to write a predicate to construct a binary search tree from a list of integer numbers.
 
Use the predicate add/3, developed in chapter 4 of the course, to write a predicate to construct a binary search tree from a list of integer numbers.
   
 
Example:
 
Example:
  +
 
<pre>
 
<pre>
 
* construct([3,2,5,7,1],T).
 
* construct([3,2,5,7,1],T).
Line 159: Line 171:
 
</pre>
 
</pre>
   
Then use this predicate to test the solution of the problem P56.
+
Then use this predicate to test the solution of Problem 56.
   
 
Example:
 
Example:
  +
 
<pre>
 
<pre>
 
* test-symmetric([5,3,18,1,4,12,21]).
 
* test-symmetric([5,3,18,1,4,12,21]).
 
Yes
 
Yes
* test-symmetric([3,2,5,7,1]).
+
* test-symmetric([3,2,5,7,4]).
 
No
 
No
 
</pre>
 
</pre>
   
 
Example in Haskell:
 
Example in Haskell:
  +
<pre>
 
  +
<haskell>
*Main> construct [3, 2, 5, 7, 1]
 
  +
λ> construct [3, 2, 5, 7, 1]
 
Branch 3 (Branch 2 (Branch 1 Empty Empty) Empty) (Branch 5 Empty (Branch 7 Empty Empty))
 
Branch 3 (Branch 2 (Branch 1 Empty Empty) Empty) (Branch 5 Empty (Branch 7 Empty Empty))
*Main> symmetric . construct $ [5, 3, 18, 1, 4, 12, 21]
+
λ> symmetric . construct $ [5, 3, 18, 1, 4, 12, 21]
 
True
 
True
*Main> symmetric . construct $ [3, 2, 5, 7, 1]
+
λ> symmetric . construct $ [3, 2, 5, 7, 1]
 
True
 
True
</pre>
 
 
Solution:
 
<haskell>
 
add :: Ord a => a -> Tree a -> Tree a
 
add x Empty = Branch x Empty Empty
 
add x t@(Branch y l r) = case compare x y of
 
LT -> Branch y (add x l) r
 
GT -> Branch y l (add x r)
 
EQ -> t
 
 
construct xs = foldl (flip add) Empty xs
 
 
</haskell>
 
</haskell>
   
Here, the definition of construct is trivial, because the pattern of accumulating from the left is captured by the standard function foldl.
 
 
 
 
== Problem 58 ==
 
== Problem 58 ==
  +
<div style="border-bottom:1px solid #eee">(**) Generate-and-test paradigm. <span style="float:right"><small>[[99 questions/Solutions/58|Solutions]]</small></span>
 
  +
</div>
(**) Generate-and-test paradigm
 
  +
&nbsp;<br>
   
 
Apply the generate-and-test paradigm to construct all symmetric, completely balanced binary trees with a given number of nodes.
 
Apply the generate-and-test paradigm to construct all symmetric, completely balanced binary trees with a given number of nodes.
   
 
Example:
 
Example:
  +
 
<pre>
 
<pre>
 
* sym-cbal-trees(5,Ts).
 
* sym-cbal-trees(5,Ts).
Line 206: Line 209:
   
 
Example in Haskell:
 
Example in Haskell:
<pre>
 
*Main> symCbalTrees 5
 
[Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' (Branch 'x' Empty Empty) Empty),Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) Empty) (Branch 'x' Empty (Branch 'x' Empty Empty))]
 
</pre>
 
   
Solution:
 
 
<haskell>
 
<haskell>
symCbalTrees = filter symmetric . cbalTree
+
λ> symCbalTrees 5
  +
[Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' (Branch 'x' Empty Empty) Empty),Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) Empty) (Branch 'x' Empty (Branch 'x' Empty Empty))]
 
</haskell>
 
</haskell>
  +
 
 
 
== Problem 59 ==
 
== Problem 59 ==
  +
<div style="border-bottom:1px solid #eee">(***) Construct height-balanced binary trees. <span style="float:right"><small>[[99 questions/Solutions/59|Solutions]]</small></span>
 
  +
</div>
(**) Construct height-balanced binary trees
 
  +
&nbsp;<br>
   
 
In a height-balanced binary tree, the following property holds for every node: The height of its left subtree and the height of its right subtree are almost equal, which means their difference is not greater than one.
 
In a height-balanced binary tree, the following property holds for every node: The height of its left subtree and the height of its right subtree are almost equal, which means their difference is not greater than one.
  +
  +
Construct a list of all height-balanced binary trees with the given element and the given maximum height.
   
 
Example:
 
Example:
  +
 
<pre>
 
<pre>
 
?- hbal_tree(3,T).
 
?- hbal_tree(3,T).
Line 231: Line 235:
   
 
Example in Haskell:
 
Example in Haskell:
  +
<pre>
 
  +
<haskell>
*Main> take 4 $ hbalTree 'x' 3
 
  +
λ> take 4 $ hbalTree 'x' 3
 
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty (Branch 'x' Empty Empty)),
 
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty (Branch 'x' Empty Empty)),
 
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) Empty),
 
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) Empty),
 
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)),
 
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)),
 
Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' Empty Empty)]
 
Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' Empty Empty)]
</pre>
+
</haskell>
   
Solution:
 
<haskell>
 
hbalTree x = map fst . hbalTree'
 
where hbalTree' 0 = [(Empty, 0)]
 
hbalTree' 1 = [(Branch x Empty Empty, 1)]
 
hbalTree' n =
 
let t = hbalTree' (n-2) ++ hbalTree' (n-1)
 
in [(Branch x lb rb, h) | (lb,lh) <- t, (rb,rh) <- t
 
, let h = 1 + max lh rh, h == n]
 
</haskell>
 
Alternative solution:
 
<haskell>
 
hbaltree :: a -> Int -> [Tree a]
 
hbaltree x 0 = [Empty]
 
hbaltree x 1 = [Branch x Empty Empty]
 
hbaltree x h = [Branch x l r |
 
(hl, hr) <- [(h-2, h-1), (h-1, h-1), (h-1, h-2)],
 
l <- hbaltree x hl, r <- hbaltree x hr]
 
</haskell>
 
If we want to avoid recomputing lists of trees (at the cost of extra space), we can use a similar structure to the common method for computation of all the Fibonacci numbers:
 
<haskell>
 
hbaltree :: a -> Int -> [Tree a]
 
hbaltree x h = trees !! h
 
where trees = [Empty] : [Branch x Empty Empty] :
 
zipWith combine (tail trees) trees
 
combine ts shortts = [Branch x l r |
 
(ls, rs) <- [(shortts, ts), (ts, ts), (ts, shortts)],
 
l <- ls, r <- rs]
 
</haskell>
 
   
 
== Problem 60 ==
 
== Problem 60 ==
  +
<div style="border-bottom:1px solid #eee">(***) Construct height-balanced binary trees with a given number of nodes. <span style="float:right"><small>[[99 questions/Solutions/60|Solutions]]</small></span>
  +
</div>
  +
&nbsp;<br>
   
(**) Construct height-balanced binary trees with a given number of nodes
+
Consider a height-balanced binary tree of height H. What is the maximum number of nodes it can contain?
Consider a height-balanced binary tree of height H.
 
What is the maximum number of nodes it can contain?
 
Clearly, MaxN = 2**H - 1.
 
However, what is the minimum number MinN?
 
This question is more difficult.
 
Try to find a recursive statement and turn it into a function <hask>minNodes</hask> that returns the minimum number of nodes in a height-balanced binary tree of height H.
 
   
  +
Clearly, MaxN = 2<sup>H</sup> - 1. However, what is the minimum number MinN? This question is more difficult. Try to find a recursive statement and turn it into a function <code>minNodes</code> that returns the minimum number of nodes in a height-balanced binary tree of height H.
On the other hand, we might ask: what is the maximum height H a height-balanced binary tree with N nodes can have?
 
Write a function <hask>maxHeight</hask> that computes this.
 
   
Now, we can attack the main problem: construct all the height-balanced binary trees with a given nuber of nodes.
+
On the other hand, we might ask: what is the maximum height H a height-balanced binary tree with N nodes can have? Write a function <code>maxHeight</code> that computes this.
   
Find out how many height-balanced trees exist for N = 15.
+
Now, we can attack the main problem: construct all the height-balanced binary trees with a given number of nodes. Find out how many height-balanced trees exist for N = 15.
   
 
Example in Prolog:
 
Example in Prolog:
  +
 
<pre>
 
<pre>
 
?- count_hbal_trees(15,C).
 
?- count_hbal_trees(15,C).
Line 293: Line 266:
   
 
Example in Haskell:
 
Example in Haskell:
  +
<pre>
 
  +
<haskell>
*Main> length $ hbalTreeNodes 'x' 15
 
  +
λ> length $ hbalTreeNodes 'x' 15
 
1553
 
1553
*Main> map (hbalTreeNodes 'x') [0,1,2,3]
+
λ> map (hbalTreeNodes 'x') [0..3]
 
[[Empty],
 
[[Empty],
 
[Branch 'x' Empty Empty],
 
[Branch 'x' Empty Empty],
 
[Branch 'x' Empty (Branch 'x' Empty Empty),Branch 'x' (Branch 'x' Empty Empty) Empty],
 
[Branch 'x' Empty (Branch 'x' Empty Empty),Branch 'x' (Branch 'x' Empty Empty) Empty],
 
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)]]
 
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)]]
</pre>
 
 
Solution:
 
<haskell>
 
hbalTreeNodes _ 0 = [Empty]
 
hbalTreeNodes x n = concatMap toFilteredTrees [minHeight .. maxHeight]
 
where toFilteredTrees = filter ((n ==) . countNodes) . hbalTree x
 
 
-- Similar to the Fibonacci sequence but adds 1 in each step.
 
minNodesSeq = 0:1:zipWith ((+).(1+)) minNodesSeq (tail minNodesSeq)
 
minNodes = (minNodesSeq !!)
 
 
minHeight = ceiling $ logBase 2 $ fromIntegral (n+1)
 
maxHeight = (fromJust $ findIndex (>n) minNodesSeq) - 1
 
 
countNodes Empty = 0
 
countNodes (Branch _ l r) = countNodes l + countNodes r + 1
 
 
 
</haskell>
 
</haskell>
Another solution generates only the trees we want:
 
<haskell>
 
-- maximum number of nodes in a weight-balanced tree of height h
 
maxNodes :: Int -> Int
 
maxNodes h = 2^h - 1
 
   
-- minimum height of a weight-balanced tree of n nodes
 
minHeight :: Int -> Int
 
minHeight n = ceiling $ logBase 2 $ fromIntegral (n+1)
 
 
-- minimum number of nodes in a weight-balanced tree of height h
 
minNodes :: Int -> Int
 
minNodes h = fibs !! (h+2) - 1
 
 
-- maximum height of a weight-balanced tree of n nodes
 
maxHeight :: Int -> Int
 
maxHeight n = length (takeWhile (<= n+1) fibs) - 3
 
 
-- Fibonacci numbers
 
fibs :: [Int]
 
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
 
 
hbalTreeNodes :: a -> Int -> [Tree a]
 
hbalTreeNodes x n = [t | h <- [minHeight n .. maxHeight n], t <- baltree h n]
 
where
 
-- baltree h n = weight-balanced trees of height h with n nodes
 
-- assuming minNodes h <= n <= maxNodes h
 
baltree 0 n = [Empty]
 
baltree 1 n = [Branch x Empty Empty]
 
baltree h n = [Branch x l r |
 
(hl,hr) <- [(h-2,h-1), (h-1,h-1), (h-1,h-2)],
 
let min_nl = max (minNodes hl) (n - 1 - maxNodes hr),
 
let max_nl = min (maxNodes hl) (n - 1 - minNodes hr),
 
nl <- [min_nl .. max_nl],
 
let nr = n - 1 - nl,
 
l <- baltree hl nl,
 
r <- baltree hr nr]
 
</haskell>
 
   
 
[[Category:Tutorials]]
 
[[Category:Tutorials]]

Latest revision as of 02:54, 11 June 2023


This is part of Ninety-Nine Haskell Problems, based on Ninety-Nine Prolog Problems.

Binary trees

A binary tree is either empty or it is composed of a root element and two successors, which are binary trees themselves. In Haskell, we can characterize binary trees with a datatype definition:

data Tree a = Empty | Branch a (Tree a) (Tree a)
              deriving (Show, Eq)

This says that a Tree of type a consists of either an Empty node, or a Branch containing one value of type a with exactly two subtrees of type a.

Given this definition, the tree in the diagram above would be represented as:

tree1 = Branch 'a' (Branch 'b' (Branch 'd' Empty Empty)
                               (Branch 'e' Empty Empty))
                   (Branch 'c' Empty
                               (Branch 'f' (Branch 'g' Empty Empty)
                                           Empty))

Since a "leaf" node is a branch with two empty subtrees, it can be useful to define a shorthand function:

leaf x = Branch x Empty Empty

Then the tree diagram above could be expressed more simply as:

tree1' = Branch 'a' (Branch 'b' (leaf 'd')
                                (leaf 'e'))
                    (Branch 'c' Empty
                                (Branch 'f' (leaf 'g')
                                            Empty)))

Other examples of binary trees:

-- A binary tree consisting of a root node only
tree2 = Branch 'a' Empty Empty

-- An empty binary tree
tree3 = Empty

-- A tree of integers
tree4 = Branch 1 (Branch 2 Empty (Branch 4 Empty Empty))
                 (Branch 2 Empty Empty)


Problem 54A

(*) Check whether a given term represents a binary tree. (no solution needed)

 

In Prolog or Lisp, one writes a predicate to do this.

Example in Lisp:

* (istree (a (b nil nil) nil))
T
* (istree (a (b nil nil)))
NIL

Note: Haskell's type system ensures that all terms of type Tree a are binary trees: it is just not possible to construct an invalid tree with this type. Hence, it is redundant to introduce a predicate to check this property: it would always return True.


Problem 55

(**) Construct completely balanced binary trees. Solutions

 

In a completely balanced binary tree, the following property holds for every node: The number of nodes in its left subtree and the number of nodes in its right subtree are almost equal, which means their difference is not greater than one.

Write a function cbal-tree to construct completely balanced binary trees for a given number of nodes. The predicate should generate all solutions via backtracking. Put the letter 'x' as information into all nodes of the tree.

Example:

* cbal-tree(4,T).
T = t(x, t(x, nil, nil), t(x, nil, t(x, nil, nil))) ;
T = t(x, t(x, nil, nil), t(x, t(x, nil, nil), nil)) ;
etc......No

Example in Haskell, whitespace and "comment diagrams" added for clarity and exposition:

λ> cbalTree 4
[
-- permutation 1
--     x
--    / \
--   x   x
--        \
--         x
Branch 'x' (Branch 'x' Empty Empty) 
           (Branch 'x' Empty 
                       (Branch 'x' Empty Empty)),

-- permutation 2
--     x
--    / \
--   x   x
--      /
--     x
Branch 'x' (Branch 'x' Empty Empty) 
           (Branch 'x' (Branch 'x' Empty Empty) 
                       Empty),

-- permutation 3
--     x
--    / \
--   x   x
--    \
--     x
Branch 'x' (Branch 'x' Empty 
                       (Branch 'x' Empty Empty)) 
           (Branch 'x' Empty Empty),

-- permutation 4
--     x
--    / \
--   x   x
--  /
-- x
Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) 
                       Empty) 
           (Branch 'x' Empty Empty)
]


Problem 56

(**) Symmetric binary trees. Solutions

 

Let us call a binary tree symmetric if you can draw a vertical line through the root node and then the right subtree is the mirror image of the left subtree. Write a predicate symmetric/1 to check whether a given binary tree is symmetric. Hint: Write a predicate mirror/2 first to check whether one tree is the mirror image of another. We are only interested in the structure, not in the contents of the nodes.

Example in Haskell:

λ> symmetric (Branch 'x' (Branch 'x' Empty Empty) Empty)
False
λ> symmetric (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty))
True


Problem 57

(**) Binary search trees. Solutions

 

Use the predicate add/3, developed in chapter 4 of the course, to write a predicate to construct a binary search tree from a list of integer numbers.

Example:

* construct([3,2,5,7,1],T).
T = t(3, t(2, t(1, nil, nil), nil), t(5, nil, t(7, nil, nil)))

Then use this predicate to test the solution of Problem 56.

Example:

* test-symmetric([5,3,18,1,4,12,21]).
Yes
* test-symmetric([3,2,5,7,4]).
No

Example in Haskell:

λ> construct [3, 2, 5, 7, 1]
Branch 3 (Branch 2 (Branch 1 Empty Empty) Empty) (Branch 5 Empty (Branch 7 Empty Empty))
λ> symmetric . construct $ [5, 3, 18, 1, 4, 12, 21]
True
λ> symmetric . construct $ [3, 2, 5, 7, 1]
True


Problem 58

(**) Generate-and-test paradigm. Solutions

 

Apply the generate-and-test paradigm to construct all symmetric, completely balanced binary trees with a given number of nodes.

Example:

* sym-cbal-trees(5,Ts).
Ts = [t(x, t(x, nil, t(x, nil, nil)), t(x, t(x, nil, nil), nil)), t(x, t(x, t(x, nil, nil), nil), t(x, nil, t(x, nil, nil)))] 

Example in Haskell:

λ> symCbalTrees 5
[Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' (Branch 'x' Empty Empty) Empty),Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) Empty) (Branch 'x' Empty (Branch 'x' Empty Empty))]


Problem 59

(***) Construct height-balanced binary trees. Solutions

 

In a height-balanced binary tree, the following property holds for every node: The height of its left subtree and the height of its right subtree are almost equal, which means their difference is not greater than one.

Construct a list of all height-balanced binary trees with the given element and the given maximum height.

Example:

?- hbal_tree(3,T).
T = t(x, t(x, t(x, nil, nil), t(x, nil, nil)), t(x, t(x, nil, nil), t(x, nil, nil))) ;
T = t(x, t(x, t(x, nil, nil), t(x, nil, nil)), t(x, t(x, nil, nil), nil)) ;
etc......No

Example in Haskell:

λ> take 4 $ hbalTree 'x' 3
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty (Branch 'x' Empty Empty)),
 Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) Empty),
 Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)),
 Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' Empty Empty)]


Problem 60

(***) Construct height-balanced binary trees with a given number of nodes. Solutions

 

Consider a height-balanced binary tree of height H. What is the maximum number of nodes it can contain?

Clearly, MaxN = 2H - 1. However, what is the minimum number MinN? This question is more difficult. Try to find a recursive statement and turn it into a function minNodes that returns the minimum number of nodes in a height-balanced binary tree of height H.

On the other hand, we might ask: what is the maximum height H a height-balanced binary tree with N nodes can have? Write a function maxHeight that computes this.

Now, we can attack the main problem: construct all the height-balanced binary trees with a given number of nodes. Find out how many height-balanced trees exist for N = 15.

Example in Prolog:

?- count_hbal_trees(15,C).
C = 1553

Example in Haskell:

λ> length $ hbalTreeNodes 'x' 15
1553
λ> map (hbalTreeNodes 'x') [0..3]
[[Empty],
 [Branch 'x' Empty Empty],
 [Branch 'x' Empty (Branch 'x' Empty Empty),Branch 'x' (Branch 'x' Empty Empty) Empty],
 [Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)]]