-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Abhijit Sarkar
committed
Jan 10, 2024
1 parent
61dcaaa
commit 9092a6d
Showing
15 changed files
with
290 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package bintree | ||
|
||
import Tree.* | ||
|
||
// P55 (**) Construct completely balanced binary trees. | ||
// 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. | ||
// | ||
// Define an object named Tree. Write a function Tree.cBalanced to | ||
// construct completely balanced binary trees for a given number of nodes. | ||
// The function should generate all solutions. The function should take as | ||
// parameters the number of nodes and a single value to put in all of them. | ||
// | ||
// scala> Tree.cBalanced(4, "x") | ||
// res0: List(Node[String]) = List(T(x T(x . .) T(x . T(x . .))), T(x T(x . .) T(x T(x . .) .)), ... | ||
|
||
object P55: | ||
private def build[A](n: Int, x: A): List[(Tree[A], Int)] = | ||
if n == 0 | ||
then Nil | ||
else if n == 1 | ||
then List((singleton(x), 1)) | ||
else if n == 2 | ||
then | ||
List( | ||
(Node(x, singleton(x), Empty), 2), | ||
(Node(x, Empty, singleton(x)), 2) | ||
) | ||
else | ||
val k = (n - 1) / 2 | ||
for | ||
(l, i) <- build(k, x) | ||
(r, j) <- build(n - k - 1, x) | ||
h = i + j + 1 | ||
xs = | ||
if math.abs(i - j) == 1 | ||
then List((Node(x, r, l), h)) | ||
else Nil | ||
y <- (Node(x, l, r), h) :: xs | ||
yield y | ||
|
||
def cBalanced[A](n: Int, x: A): List[Tree[A]] = | ||
build(n, x).map(_._1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package bintree | ||
|
||
import Tree.* | ||
|
||
// P56 (**) Symmetric binary trees. | ||
// 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. Add an isSymmetric method to the Tree class to check | ||
// whether a given binary tree is symmetric. Hint: Write an isMirrorOf | ||
// method 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. | ||
// | ||
// scala> Node('a', Node('b'), Node('c')).isSymmetric | ||
// res0: Boolean = true | ||
|
||
object P56: | ||
private def isMirror[A](t1: Tree[A], t2: Tree[A]): Boolean = | ||
(t1, t2) match | ||
case (Empty, Empty) => true | ||
case (Empty, _) => false | ||
case (_, Empty) => false | ||
case (Node(_, l1, r1), Node(_, l2, r2)) => | ||
isMirror(l1, r2) && isMirror(r1, l2) | ||
|
||
extension [A](t: Tree[A]) | ||
def isSymmetric: Boolean = t match | ||
case Empty => true | ||
case Node(_, l, r) => isMirror(l, r) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package bintree | ||
|
||
import Tree.* | ||
import math.Ordered.orderingToOrdered | ||
|
||
// P57 (**) Binary search trees (dictionaries). | ||
// Write a function to add an element to a binary search tree. | ||
// | ||
// scala> End.addValue(2) | ||
// res0: Node[Int] = T(2 . .) | ||
// | ||
// scala> res0.addValue(3) | ||
// res1: Node[Int] = T(2 . T(3 . .)) | ||
// | ||
// scala> res1.addValue(0) | ||
// res2: Node[Int] = T(2 T(0 . .) T(3 . .)) | ||
// | ||
// Hint: The abstract definition of addValue in Tree should be | ||
// `def addValue[U >: T <% Ordered[U]](x: U): Tree[U]`. The `>: T` is | ||
// because addValue's parameters need to be _contravariant_ in T. | ||
// (Conceptually, we're adding nodes above existing nodes. In order for the | ||
// subnodes to be of type T or any subtype, the upper nodes must be of type | ||
// T or any supertype.) The `<% Ordered[U]` allows us to use the < operator | ||
// on the values in the tree. | ||
// | ||
// Use that function to construct a binary tree from a list of integers. | ||
// | ||
// scala> Tree.fromList(List(3, 2, 5, 7, 1)) | ||
// res3: Node[Int] = T(3 T(2 T(1 . .) .) T(5 . T(7 . .))) | ||
// | ||
// Finally, use that function to test your solution to P56. | ||
// | ||
// scala> Tree.fromList(List(5, 3, 18, 1, 4, 12, 21)).isSymmetric | ||
// res4: Boolean = true | ||
// | ||
// scala> Tree.fromList(List(3, 2, 5, 7, 4)).isSymmetric | ||
// res5: Boolean = false | ||
|
||
object P57: | ||
extension [A](t: Tree[A]) | ||
// "covariant type A occurs in contravariant position". | ||
// If we allow any subtype of A, then a list of cats | ||
// may contain a dog! | ||
// https://stackoverflow.com/a/43180701/839733 | ||
def addValue[B >: A](x: B)(using Ordering[B]): Tree[B] = t match | ||
case Empty => singleton(x) | ||
case Node(y, l, r) if x < y => | ||
val left = l.addValue(x) | ||
Node(y, left, r) | ||
case Node(y, l, r) => | ||
val right = r.addValue(x) | ||
Node(y, l, right) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package bintree | ||
|
||
import P56.* | ||
|
||
// P58 (**) Generate-and-test paradigm. | ||
// Apply the generate-and-test paradigm to construct all symmetric, | ||
// completely balanced binary trees with a given number of nodes. | ||
// | ||
// scala> Tree.symmetricBalancedTrees(5, "x") | ||
// res0: List[Node[String]] = List(T(x T(x . T(x . .)) T(x T(x . .) .)), T(x T(x T(x . .) .) T(x . T(x . .)))) | ||
|
||
object P58: | ||
def symmetricBalancedTrees[A](n: Int, x: A): List[Tree[A]] = | ||
P55.cBalanced(n, x).filter(_.isSymmetric) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package bintree | ||
|
||
import Tree.* | ||
|
||
// P59 (**) Construct height-balanced binary trees. | ||
// 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. | ||
// | ||
// Write a method Tree.hbalTrees to construct height-balanced binary trees | ||
// for a given height with a supplied value for the nodes. The function | ||
// should generate all solutions. | ||
// | ||
// scala> Tree.hbalTrees(3, "x") | ||
// res0: List[Node[String]] = List(T(x T(x T(x . .) T(x . .)) T(x T(x . .) T(x . .))), T(x T(x T(x . .) T(x . .)) T(x T(x . .) .)), ... | ||
|
||
object P59: | ||
def hbalTrees[A](h: Int, x: A): List[Tree[A]] = | ||
if h == 0 | ||
then Nil | ||
else if h == 1 | ||
then List(singleton(x)) | ||
else if h == 2 | ||
then | ||
List( | ||
Node(x, singleton(x), Empty), | ||
Node(x, Empty, singleton(x)), | ||
Node(x, singleton(x), singleton(x)) | ||
) | ||
else | ||
for | ||
a <- hbalTrees(h - 1, x) | ||
b <- hbalTrees(h - 2, x) | ||
c <- List( | ||
Node(x, a, b), | ||
Node(x, b, a), | ||
Node(x, a, a) | ||
) | ||
yield c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package bintree | ||
|
||
enum Tree[+A]: | ||
case Empty | ||
case Node(value: A, left: Tree[A], right: Tree[A]) | ||
|
||
object Tree: | ||
def empty[A]: Tree[A] = Empty | ||
|
||
def singleton[A](x: A): Tree[A] = | ||
Node(x, Empty, Empty) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package bintree | ||
|
||
import munit.FunSuite | ||
import Tree.* | ||
|
||
class P55Suite extends FunSuite: | ||
test("construct completely balanced binary trees"): | ||
val data = List( | ||
(0, Nil), | ||
(1, List(singleton('x'))), | ||
(2, List(Node('x', singleton('x'), Empty), Node('x', Empty, singleton('x')))), | ||
(3, (List(Node('x', singleton('x'), singleton('x'))))), | ||
( | ||
4, | ||
List( | ||
Node('x', singleton('x'), Node('x', singleton('x'), Empty)), | ||
Node('x', Node('x', singleton('x'), Empty), singleton('x')), | ||
Node('x', singleton('x'), Node('x', Empty, singleton('x'))), | ||
Node('x', Node('x', Empty, singleton('x')), singleton('x')) | ||
) | ||
) | ||
) | ||
data.foreach { (n, expected) => | ||
val obtained = P55.cBalanced(n, 'x') | ||
assertEquals(obtained.size, expected.size) | ||
obtained.foreach { tree => | ||
assert(expected.contains(tree), s"Tree: $tree") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package bintree | ||
|
||
import munit.FunSuite | ||
import Tree.* | ||
import P56.* | ||
|
||
class P56Suite extends FunSuite: | ||
test("check whether a given binary tree is symmetric"): | ||
val obtained = Node('a', singleton('b'), Empty).isSymmetric | ||
assertEquals(obtained, false) | ||
|
||
val obtained2 = Node('a', singleton('b'), singleton('c')).isSymmetric | ||
assertEquals(obtained2, true) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package bintree | ||
|
||
import munit.FunSuite | ||
import Tree.* | ||
import P56.* | ||
import P57.* | ||
|
||
class P57Suite extends FunSuite: | ||
test("add an element to a BST"): | ||
val xs = List(3, 2, 5, 7, 1) | ||
val obtained = xs.foldLeft(Tree.empty[Int])((t, x) => t.addValue(x)) | ||
assertEquals(obtained.isSymmetric, true) | ||
|
||
val ys = List(3, 2, 5, 7, 4) | ||
val obtained2 = ys.foldLeft(Tree.empty[Int])((t, x) => t.addValue(x)) | ||
assertEquals(obtained2.isSymmetric, false) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package bintree | ||
|
||
import munit.FunSuite | ||
import Tree.* | ||
|
||
class P58Suite extends FunSuite: | ||
test("construct all symmetric, completely balanced binary trees with a given number of nodes"): | ||
val obtained = P58.symmetricBalancedTrees(5, 'x') | ||
val expected = List( | ||
Node('x', Node('x', Empty, singleton('x')), Node('x', singleton('x'), Empty)), | ||
Node('x', Node('x', singleton('x'), Empty), Node('x', Empty, singleton('x'))) | ||
) | ||
assertEquals(obtained.size, expected.size) | ||
obtained.foreach { tree => | ||
assert(expected.contains(tree), s"Tree: $tree") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package bintree | ||
|
||
import munit.FunSuite | ||
import Tree.* | ||
|
||
class P59Suite extends FunSuite: | ||
test("construct height-balanced binary trees"): | ||
val obtained = P59.hbalTrees(3, 'x') | ||
val expected = List( | ||
Node('x', Node('x', Empty, Empty), Node('x', Empty, singleton('x'))), | ||
Node('x', Node('x', Empty, Empty), Node('x', singleton('x'), Empty)), | ||
Node('x', Node('x', Empty, Empty), Node('x', singleton('x'), singleton('x'))), | ||
Node('x', Node('x', Empty, singleton('x')), Node('x', Empty, Empty)) | ||
) | ||
expected.foreach { tree => | ||
assert(obtained.contains(tree), s"Tree: $tree") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters