From e636bfaa9bc760d08a6c5ac520fd0b25acf1c77d Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Mon, 7 Jan 2019 20:58:20 +0800 Subject: [PATCH 01/19] impl visit tree --- .../scala/ch23_binary_tree/BinaryTree.scala | 39 +++++++++++++++ .../ch23_binary_tree/BinaryTreeTest.scala | 48 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 scala/src/main/scala/ch23_binary_tree/BinaryTree.scala create mode 100644 scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala diff --git a/scala/src/main/scala/ch23_binary_tree/BinaryTree.scala b/scala/src/main/scala/ch23_binary_tree/BinaryTree.scala new file mode 100644 index 0000000..efc6bce --- /dev/null +++ b/scala/src/main/scala/ch23_binary_tree/BinaryTree.scala @@ -0,0 +1,39 @@ +package ch23_binary_tree + +class Node[T](var data: T, var left: Option[Node[T]], var right: Option[Node[T]]) + +class BinaryTree[T] { + + def preOrder(root: Option[Node[T]]): String = { + val result = new StringBuilder + + if (root.isDefined) { + result.append(root.map(_.data.toString).get) + result.append(preOrder(root.get.left)) + result.append(preOrder(root.get.right)) + } + result.mkString + } + + def inOrder(root: Option[Node[T]]): String = { + val result = new StringBuilder + + if (root.isDefined) { + result.append(inOrder(root.get.left)) + result.append(root.map(_.data.toString).get) + result.append(inOrder(root.get.right)) + } + result.mkString + } + + def postOrder(root: Option[Node[T]]): String = { + val result = new StringBuilder + + if (root.isDefined) { + result.append(postOrder(root.get.left)) + result.append(postOrder(root.get.right)) + result.append(root.map(_.data.toString).get) + } + result.mkString + } +} diff --git a/scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala b/scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala new file mode 100644 index 0000000..2ee3f95 --- /dev/null +++ b/scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala @@ -0,0 +1,48 @@ +package ch23_binary_tree + +import org.scalatest.{BeforeAndAfterEach, FlatSpec, Matchers} + +class BinaryTreeTest extends FlatSpec with BeforeAndAfterEach with Matchers { + + /* + * A + * / \ + * B C + * / \ / \ + * D E F G + * + */ + var root:Option[Node[String]] = None + val tree = new BinaryTree[String] + + override def beforeEach() { + val D = new Node[String]("D", None, None) + val E = new Node[String]("E", None, None) + val B = new Node[String]("B", Some(D), Some(E)) + val F = new Node[String]("F", None, None) + val G = new Node[String]("G", None, None) + val C = new Node[String]("C", Some(F), Some(G)) + val A = new Node[String]("A", Some(B), Some(C)) + root = Some(A) + } + + override protected def afterEach(): Unit = { + root = None + } + + behavior of "BinaryTreeTest" + + it should "postOrder" in { + tree.postOrder(root) should equal("DEBFGCA") + } + + it should "inOrder" in { + tree.inOrder(root) should equal("DBEAFCG") + } + + it should "preOrder" in { + tree.preOrder(root) should equal("ABDECFG") + } + + +} From 495415b45cc9971d1d2da4ceed23a8e7a4015c6d Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Mon, 7 Jan 2019 21:18:18 +0800 Subject: [PATCH 02/19] impl level order --- .../scala/ch23_binary_tree/BinaryTree.scala | 22 +++++++++++++++++++ .../ch23_binary_tree/BinaryTreeTest.scala | 6 +++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/scala/src/main/scala/ch23_binary_tree/BinaryTree.scala b/scala/src/main/scala/ch23_binary_tree/BinaryTree.scala index efc6bce..3dfed76 100644 --- a/scala/src/main/scala/ch23_binary_tree/BinaryTree.scala +++ b/scala/src/main/scala/ch23_binary_tree/BinaryTree.scala @@ -1,5 +1,7 @@ package ch23_binary_tree +import scala.collection.mutable + class Node[T](var data: T, var left: Option[Node[T]], var right: Option[Node[T]]) class BinaryTree[T] { @@ -36,4 +38,24 @@ class BinaryTree[T] { } result.mkString } + + def levelOrder(root: Option[Node[T]]): String = { + val result = new StringBuilder + val queue = new mutable.Queue[Node[T]]() + if (root.isDefined) { + queue += root.get + while (!queue.isEmpty) { + val node = queue.dequeue() + result.append(node.data.toString) + if (node.left.isDefined) { + queue += node.left.get + } + if (node.right.isDefined) { + queue += node.right.get + } + } + } + + result.mkString + } } diff --git a/scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala b/scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala index 2ee3f95..0767f84 100644 --- a/scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala +++ b/scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala @@ -12,7 +12,7 @@ class BinaryTreeTest extends FlatSpec with BeforeAndAfterEach with Matchers { * D E F G * */ - var root:Option[Node[String]] = None + var root: Option[Node[String]] = None val tree = new BinaryTree[String] override def beforeEach() { @@ -44,5 +44,7 @@ class BinaryTreeTest extends FlatSpec with BeforeAndAfterEach with Matchers { tree.preOrder(root) should equal("ABDECFG") } - + it should "levelOrder" in { + tree.levelOrder(root) should equal("ABCDEFG") + } } From c7bea977cfdca40da7614985cdbc6fee71e4d202 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 8 Jan 2019 13:20:42 +0800 Subject: [PATCH 03/19] insert and find BST --- .../BinarySearchTree.scala | 59 +++++++++++++++++++ .../BinarySearchTreeTest.scala | 43 ++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala create mode 100644 scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala diff --git a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala new file mode 100644 index 0000000..9c35fb2 --- /dev/null +++ b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala @@ -0,0 +1,59 @@ +package ch24_binary_search_tree + +import ch23_binary_tree.{BinaryTree, Node} + +import scala.util.control.Breaks._ + +class BinarySearchTree(var root: Option[Node[Int]]) extends BinaryTree[Int] { + + def insert(data: Int): Node[Int] = { + val dataNode = new Node(data, None, None) + root match { + case None => root = Some(dataNode) + case Some(_) => { + var p = root + breakable { + while (p.isDefined) { + if (data > p.get.data) { + p.get.right match { + case None => { + p.get.right = Some(dataNode) + break + } + case Some(_) => p = p.get.right + } + } + if (data < p.get.data) { + p.get.left match { + case None => { + p.get.left = Some(dataNode) + break + } + case Some(_) => p = p.get.left + } + } + } + } + } + } + + dataNode + } + + def find(data: Int): Option[Node[Int]] = { + var p = root + breakable { + while (p.isDefined) { + if (data > p.get.data) { + p = p.get.right + } else if (data < p.get.data) { + p = p.get.left + } else { + //find the value + break + } + } + } + p + } +} diff --git a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala new file mode 100644 index 0000000..d00d418 --- /dev/null +++ b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala @@ -0,0 +1,43 @@ +package ch24_binary_search_tree + +import org.scalatest.{FlatSpec, Matchers} + +class BinarySearchTreeTest extends FlatSpec with Matchers { + + /* + * 33 + * / \ + * 17 50 + * / \ / \ + * 13 18 34 58 + * \ \ / \ + * 16 25 51 66 + * / \ \ + * 19 27 55 + * + */ + behavior of "BinarySearchTreeTest" + + it should "insert" in { + val tree = new BinarySearchTree(None) + val nums = Array(33, 17, 50, 13, 18, 34, 58, 16, 25, 51, 66, 19, 27, 55) + nums.foreach(tree.insert) + tree.inOrder(tree.root) should equal(nums.sorted.mkString("")) + tree.preOrder(tree.root) should equal("3317131618251927503458515566") + tree.postOrder(tree.root) should equal("1613192725181734555166585033") + tree.levelOrder(tree.root) should equal("3317501318345816255166192755") + } + + it should "find " in { + val tree = new BinarySearchTree(None) + val nums = Array(33, 17, 50, 13, 18, 34, 58, 16, 25, 51, 66, 19, 27, 55) + nums.foreach(tree.insert) + + nums.foreach(num => { + assert(tree.find(num).isDefined) + tree.find(num).get.data should equal(num) + }) + assert(tree.find(100).isEmpty) + } + +} From 0f9dd9012db0cfacd44f1379f4e69e4aaad7033a Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 8 Jan 2019 13:57:39 +0800 Subject: [PATCH 04/19] impl delete for BST --- .../BinarySearchTree.scala | 72 +++++++++++++++++++ .../BinarySearchTreeTest.scala | 12 ++++ 2 files changed, 84 insertions(+) diff --git a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala index 9c35fb2..6e6d0ed 100644 --- a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala +++ b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala @@ -56,4 +56,76 @@ class BinarySearchTree(var root: Option[Node[Int]]) extends BinaryTree[Int] { } p } + + def delete(data: Int): Unit = { + //there are 3 scenarios + //1: data is leaf node + //2: data has one child node + //3: data has two child nodes, we need to find out the smallest node from right branch + var p = root + var pp: Option[Node[Int]] = None //parent node of deleted node + + //find matching node to delete + breakable { + while (p.isDefined) { + if (data > p.get.data) { + pp = p + p = p.get.right + } else if (data < p.get.data) { + pp = p + p = p.get.left + } else { + //find the value + break + } + } + } + + if (p.isEmpty) { + //find nothing + return + } + + //now we find the node to delete + //scenario 3 + if (p.get.left.isDefined && p.get.right.isDefined) { + //need to find out the smallest node in right branch + var minPP = p + var minP = p.get.right + while (minP.get.left.isDefined) { + minPP = minP + minP = minP.get.left + } + + //assign the smallest value in the right branch to the node to be deleted + p.get.data = minP.get.data + //now problems becomes delete the minP in the tree + //minP must not have any left child node + //minP may or may not have right child node + //it will fall back to scenario 1 or 2 + p = minP + pp = minPP + } + + //child is the child of p + var child: Option[Node[Int]] = None + if (p.get.left.isDefined) { + child = p.get.left + } else if (p.get.right.isDefined) { + child = p.get.right + } + + //starting the node deletion + pp match { + case None => root = child + case Some(parentNode) => { + if (parentNode.left.isDefined && (parentNode.left.get.data == p.get.data)) { + parentNode.left = child + } else if (parentNode.right.isDefined && (parentNode.right.get.data == p.get.data)) { + parentNode.right = child + } + } + } + + } } diff --git a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala index d00d418..9dbbe47 100644 --- a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala +++ b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala @@ -40,4 +40,16 @@ class BinarySearchTreeTest extends FlatSpec with Matchers { assert(tree.find(100).isEmpty) } + it should "delete" in { + val tree = new BinarySearchTree(None) + val nums = Array(33, 17, 50, 13, 18, 34, 58, 16, 25, 51, 66, 19, 27, 55) + nums.foreach(tree.insert) + tree.delete(13) + tree.inOrder(tree.root) should equal(nums.sorted.tail.mkString("")) + tree.delete(18) + tree.inOrder(tree.root) should equal("1617" + nums.sorted.slice(4, nums.size).mkString("")) + tree.delete(66) + tree.inOrder(tree.root) should equal("1617" + nums.sorted.slice(4, nums.size-1).mkString("")) + } + } From 7c5c5c4618600591f2842436284a8ee58e12a2e0 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 8 Jan 2019 14:30:55 +0800 Subject: [PATCH 05/19] tune code --- .../main/scala/ch24_binary_search_tree/BinarySearchTree.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala index 6e6d0ed..97dd7e1 100644 --- a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala +++ b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala @@ -119,9 +119,9 @@ class BinarySearchTree(var root: Option[Node[Int]]) extends BinaryTree[Int] { pp match { case None => root = child case Some(parentNode) => { - if (parentNode.left.isDefined && (parentNode.left.get.data == p.get.data)) { + if (parentNode.left == p) { parentNode.left = child - } else if (parentNode.right.isDefined && (parentNode.right.get.data == p.get.data)) { + } else if (parentNode.right == p) { parentNode.right = child } } From f8349a00989fda0239f325959caeea356f2b0a36 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 8 Jan 2019 14:45:07 +0800 Subject: [PATCH 06/19] dev hight --- .../BinarySearchTree.scala | 17 +++++++++++++++++ .../BinarySearchTreeTest.scala | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala index 97dd7e1..548c522 100644 --- a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala +++ b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala @@ -128,4 +128,21 @@ class BinarySearchTree(var root: Option[Node[Int]]) extends BinaryTree[Int] { } } + + def hight(): Int = { + _hight(root) + } + + private[this] def _hight(nodeOpt: Option[Node[Int]]): Int = { + nodeOpt match { + case None => 0 + case Some(node) => { + if (node.left.isEmpty && node.right.isEmpty) { + 1 + } else { + scala.math.max(_hight(node.left), _hight(node.right)) + 1 + } + } + } + } } diff --git a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala index 9dbbe47..070283c 100644 --- a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala +++ b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala @@ -49,7 +49,21 @@ class BinarySearchTreeTest extends FlatSpec with Matchers { tree.delete(18) tree.inOrder(tree.root) should equal("1617" + nums.sorted.slice(4, nums.size).mkString("")) tree.delete(66) - tree.inOrder(tree.root) should equal("1617" + nums.sorted.slice(4, nums.size-1).mkString("")) + tree.inOrder(tree.root) should equal("1617" + nums.sorted.slice(4, nums.size - 1).mkString("")) + } + + it should "calc hight of a tree -1" in { + val tree = new BinarySearchTree(None) + val nums = Array(33, 17, 50, 13, 18, 34, 58, 16, 25, 51, 66, 19, 27, 55) + nums.foreach(tree.insert) + tree.hight() should equal(5) + } + + it should "calc hight of a tree -2" in { + val tree = new BinarySearchTree(None) + val nums = Array(33, 17, 50, 13, 18, 34, 88).sorted + nums.foreach(tree.insert) + tree.hight() should equal(7) } } From 7d8e5c78194c2531d31b365f2942df9baa3f6031 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 8 Jan 2019 14:46:18 +0800 Subject: [PATCH 07/19] typo --- .../scala/ch24_binary_search_tree/BinarySearchTree.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala index 548c522..51e381f 100644 --- a/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala +++ b/scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala @@ -129,18 +129,18 @@ class BinarySearchTree(var root: Option[Node[Int]]) extends BinaryTree[Int] { } - def hight(): Int = { - _hight(root) + def height(): Int = { + _height(root) } - private[this] def _hight(nodeOpt: Option[Node[Int]]): Int = { + private[this] def _height(nodeOpt: Option[Node[Int]]): Int = { nodeOpt match { case None => 0 case Some(node) => { if (node.left.isEmpty && node.right.isEmpty) { 1 } else { - scala.math.max(_hight(node.left), _hight(node.right)) + 1 + scala.math.max(_height(node.left), _height(node.right)) + 1 } } } From 5585fefe24701cb98af11ab82b3f556bca5b013c Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 8 Jan 2019 14:47:41 +0800 Subject: [PATCH 08/19] more test --- .../BinarySearchTreeTest.scala | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala index 070283c..a6b24a4 100644 --- a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala +++ b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala @@ -56,14 +56,21 @@ class BinarySearchTreeTest extends FlatSpec with Matchers { val tree = new BinarySearchTree(None) val nums = Array(33, 17, 50, 13, 18, 34, 58, 16, 25, 51, 66, 19, 27, 55) nums.foreach(tree.insert) - tree.hight() should equal(5) + tree.height() should equal(5) } it should "calc hight of a tree -2" in { val tree = new BinarySearchTree(None) val nums = Array(33, 17, 50, 13, 18, 34, 88).sorted nums.foreach(tree.insert) - tree.hight() should equal(7) + tree.height() should equal(7) + } + + it should "calc hight of a tree -3" in { + val tree = new BinarySearchTree(None) + val nums = Array(33).sorted + nums.foreach(tree.insert) + tree.height() should equal(1) } } From f7c05e8e047674b468532d34f9b7ecc428f8ba99 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 8 Jan 2019 14:48:06 +0800 Subject: [PATCH 09/19] typo --- .../ch24_binary_search_tree/BinarySearchTreeTest.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala index a6b24a4..771cbe4 100644 --- a/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala +++ b/scala/src/test/scala/ch24_binary_search_tree/BinarySearchTreeTest.scala @@ -52,21 +52,21 @@ class BinarySearchTreeTest extends FlatSpec with Matchers { tree.inOrder(tree.root) should equal("1617" + nums.sorted.slice(4, nums.size - 1).mkString("")) } - it should "calc hight of a tree -1" in { + it should "calc height of a tree -1" in { val tree = new BinarySearchTree(None) val nums = Array(33, 17, 50, 13, 18, 34, 58, 16, 25, 51, 66, 19, 27, 55) nums.foreach(tree.insert) tree.height() should equal(5) } - it should "calc hight of a tree -2" in { + it should "calc height of a tree -2" in { val tree = new BinarySearchTree(None) val nums = Array(33, 17, 50, 13, 18, 34, 88).sorted nums.foreach(tree.insert) tree.height() should equal(7) } - it should "calc hight of a tree -3" in { + it should "calc height of a tree -3" in { val tree = new BinarySearchTree(None) val nums = Array(33).sorted nums.foreach(tree.insert) From 009ef35e7abd794866d4b2c2b7469cc62719ef66 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 9 Jan 2019 18:59:58 +0800 Subject: [PATCH 10/19] heap insert and remove from head --- scala/src/main/scala/ch28_heap/Heap.scala | 68 +++++++++++++++++++ scala/src/test/scala/ch28_heap/HeapTest.scala | 18 +++++ 2 files changed, 86 insertions(+) create mode 100644 scala/src/main/scala/ch28_heap/Heap.scala create mode 100644 scala/src/test/scala/ch28_heap/HeapTest.scala diff --git a/scala/src/main/scala/ch28_heap/Heap.scala b/scala/src/main/scala/ch28_heap/Heap.scala new file mode 100644 index 0000000..b481e0d --- /dev/null +++ b/scala/src/main/scala/ch28_heap/Heap.scala @@ -0,0 +1,68 @@ +package ch28_heap + +import scala.util.control.Breaks._ + +class Heap(val capacity: Int, var elementCount: Int = 0) { + + require(capacity > 0, "capacity should be > 0") + val array: Array[Int] = new Array[Int](capacity) + + def insert(data: Int): Unit = { + if (elementCount == capacity - 1) { + throw new IllegalStateException("heap full") + } + + elementCount += 1 + array(elementCount) = data + + //heapify bottom up + //compare the element with it's parent node i/2 until parent node > child node + //this will make sure the root element of the tree is the biggest value + var i = elementCount + while (i / 2 > 0 && array(i) > array(i / 2)) { + val temp = array(i) + array(i) = array(i / 2) + array(i / 2) = temp + i = i / 2 + } + + } + + def removeMax(): Int = { + require(elementCount > 0, "heap is empty") + val result = array(1) + elementCount -= 1 + array(1) = array(elementCount) + heapifyTopDown(1, elementCount - 1) + result + } + + //heapify from top to bottom + //start from the top to compare with it's child nodes + //swap if child node > parent node + //stop at child node <= parent node + private[this] def heapifyTopDown(startIndex: Int, stopIndex: Int) = { + var pointer = startIndex + breakable { + while (true) { + var maxPos = pointer + if (pointer * 2 <= stopIndex && array(pointer * 2) > array(maxPos)) { + maxPos = pointer * 2 + } + if (pointer * 2 <= stopIndex && array(pointer * 2 + 1) > array(maxPos)) { + maxPos = pointer * 2 + 1 + } + if (maxPos == pointer) { + break + } + //swap the parent and child + val temp = array(pointer) + array(pointer) = array(maxPos) + array(maxPos) = temp + //start a new round + pointer = maxPos + } + } + } + +} diff --git a/scala/src/test/scala/ch28_heap/HeapTest.scala b/scala/src/test/scala/ch28_heap/HeapTest.scala new file mode 100644 index 0000000..af5fe20 --- /dev/null +++ b/scala/src/test/scala/ch28_heap/HeapTest.scala @@ -0,0 +1,18 @@ +package ch28_heap + +import org.scalatest.{FlatSpec, Matchers} + +class HeapTest extends FlatSpec with Matchers { + + behavior of "HeapTest" + + it should "insert and removeMax" in { + val nums = Array(33, 27, 21, 16, 13, 15, 19, 5, 6, 7, 8, 1, 2, 12) + val heap = new Heap(nums.length + 1) + nums.foreach(heap.insert) + + heap.removeMax() should equal(33) + heap.removeMax() should equal(27) + } + +} From ad0d1220ec29aa82e41d5ba5b8140b50830c7245 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 9 Jan 2019 20:16:48 +0800 Subject: [PATCH 11/19] impl heap sort --- scala/src/main/scala/ch28_heap/Heap.scala | 29 ++++++++++++++++++- .../src/test/scala/ch11_sorts/SortsTest.scala | 2 ++ scala/src/test/scala/ch28_heap/HeapTest.scala | 25 ++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/scala/src/main/scala/ch28_heap/Heap.scala b/scala/src/main/scala/ch28_heap/Heap.scala index b481e0d..6bbbd6e 100644 --- a/scala/src/main/scala/ch28_heap/Heap.scala +++ b/scala/src/main/scala/ch28_heap/Heap.scala @@ -4,6 +4,22 @@ import scala.util.control.Breaks._ class Heap(val capacity: Int, var elementCount: Int = 0) { + def this(arrayParam: Array[Int], bottomUp: Boolean) = { + this(arrayParam.length + 1) + if (bottomUp) { + arrayParam.foreach(this.insert) + } else { + //copy data into array of heap + for (i <- arrayParam.indices) { + array(i + 1) = arrayParam(i) + elementCount = arrayParam.length + } + for (i <- elementCount / 2 + 1 to 1 by -1) { + heapifyTopDown(i, elementCount - 1) + } + } + } + require(capacity > 0, "capacity should be > 0") val array: Array[Int] = new Array[Int](capacity) @@ -41,7 +57,7 @@ class Heap(val capacity: Int, var elementCount: Int = 0) { //start from the top to compare with it's child nodes //swap if child node > parent node //stop at child node <= parent node - private[this] def heapifyTopDown(startIndex: Int, stopIndex: Int) = { + private[this] def heapifyTopDown(startIndex: Int, stopIndex: Int) = { var pointer = startIndex breakable { while (true) { @@ -66,3 +82,14 @@ class Heap(val capacity: Int, var elementCount: Int = 0) { } } + +object Heap { + def heapSort(array: Array[Int]): Array[Int] = { + val result = new Array[Int](array.length) + val heap = new Heap(array, true) + for (i <- result.length - 1 to 0 by -1) { + result(i) = heap.removeMax() + } + result + } +} \ No newline at end of file diff --git a/scala/src/test/scala/ch11_sorts/SortsTest.scala b/scala/src/test/scala/ch11_sorts/SortsTest.scala index d18854a..ed5eeb1 100644 --- a/scala/src/test/scala/ch11_sorts/SortsTest.scala +++ b/scala/src/test/scala/ch11_sorts/SortsTest.scala @@ -1,6 +1,7 @@ package ch11_sorts import ch12_sorts.{MergeSort, QuickSort} +import ch28_heap.Heap import org.scalatest.{FlatSpec, Matchers} import scala.util.Random @@ -53,6 +54,7 @@ class SortsTest extends FlatSpec with Matchers { timed("selectionSort", Sorts.selectionSort, array.clone()) timed("mergeSort", MergeSort.mergeSort, array.clone()) timed("quickSort", QuickSort.quickSort, array.clone()) + timed("heapSort", Heap.heapSort, array.clone()) } def reportElapsed(name: String, time: Long): Unit = println(name + " takes in " + time + "ms") diff --git a/scala/src/test/scala/ch28_heap/HeapTest.scala b/scala/src/test/scala/ch28_heap/HeapTest.scala index af5fe20..c6312e9 100644 --- a/scala/src/test/scala/ch28_heap/HeapTest.scala +++ b/scala/src/test/scala/ch28_heap/HeapTest.scala @@ -15,4 +15,29 @@ class HeapTest extends FlatSpec with Matchers { heap.removeMax() should equal(27) } + it should "build heap from array - bottom up" in { + val nums = Array(33, 27, 21, 16, 13, 15, 19, 5, 6, 7, 8, 1, 2, 12) + val heap = new Heap(nums, true) + + heap.removeMax() should equal(33) + heap.removeMax() should equal(27) + } + + it should "build heap from array - top down" in { + val nums = Array(33, 27, 21, 16, 13, 15, 19, 5, 6, 7, 8, 1, 2, 12) + val heap = new Heap(nums, false) + + heap.removeMax() should equal(33) + heap.removeMax() should equal(27) + } + + it should "sort array" in { + it should "build heap from array - top down" in { + val nums = Array(33, 27, 21, 16, 13, 15, 19, 5, 6, 7, 8, 1, 2, 12) + val result = Heap.heapSort(nums) + + result.mkString("") should equal(nums.sorted.mkString("")) + } + } + } From 62328ba803b546404be00bab75825a132053c1ba Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 9 Jan 2019 21:54:02 +0800 Subject: [PATCH 12/19] FileMerger and Unit Test --- .../ch29_heap_solutions/FileMerger.scala | 46 ++++++++++++++++ .../ch29_heap_solutions/FileMergerTest.scala | 52 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 scala/src/main/scala/ch29_heap_solutions/FileMerger.scala create mode 100644 scala/src/test/scala/ch29_heap_solutions/FileMergerTest.scala diff --git a/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala b/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala new file mode 100644 index 0000000..872ca1c --- /dev/null +++ b/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala @@ -0,0 +1,46 @@ +package ch29_heap_solutions + +import java.io.{BufferedWriter, File, FileWriter} + +import scala.collection.mutable +import scala.io.Source +import scala.util.control.Breaks._ + +object FileMerger { + + /** + * each given file has sorted String as content, we need to merge them together + * + * @param smallFiles - small files with sorted content + * @return merged file + */ + def mergeFiles(smallFiles: List[File]): File = { + //init output file + val output = File.createTempFile("merged-file", ".txt") + val writer = new BufferedWriter(new FileWriter(output)) + //init small top heap + val priorityQueue = new mutable.PriorityQueue[Tuple2[Char, Source]]()(Ordering.by((_: (Char, Source))._1).reverse) + val sources = smallFiles.toArray.map(smallFile => Source.fromFile(smallFile)) + //init fill the priority queue from each file + sources.foreach(source => priorityQueue.enqueue(Tuple2(source.next(), source))) + + breakable { + while (true) { + val next = priorityQueue.dequeue() + val output: Char = next._1 + val source = next._2 + writer.append(output) + if (source.hasNext) { + priorityQueue.enqueue(Tuple2(source.next(), source)) + } + //determine the end of merge + if (sources.forall(!_.hasNext)) { + break + } + } + } + + writer.close() + output + } +} diff --git a/scala/src/test/scala/ch29_heap_solutions/FileMergerTest.scala b/scala/src/test/scala/ch29_heap_solutions/FileMergerTest.scala new file mode 100644 index 0000000..4bc24cb --- /dev/null +++ b/scala/src/test/scala/ch29_heap_solutions/FileMergerTest.scala @@ -0,0 +1,52 @@ +package ch29_heap_solutions + +import java.io.{BufferedWriter, File, FileWriter} + +import org.scalatest.{FlatSpec, Matchers} + +import scala.io.Source +import scala.util.Random + +class FileMergerTest extends FlatSpec with Matchers { + + behavior of "FileMergerTest" + + it should "mergeFiles" in { + val num = 10 + val contentCount = 10 + val random = Random.alphanumeric + val files = new Array[File](num) + for (i <- Range(0, num)) { + val file = File.createTempFile(i + "-small", ".txt") + files(i) = file + val writer = new BufferedWriter(new FileWriter(file)) + val content = random.take((i + 1) * contentCount).toArray.slice(i * contentCount, (i + 1) * contentCount) + + writer.write(content.sorted) + writer.flush() + writer.close() + } + println("small files below") + files.foreach(printFile) + + val mergedFile = FileMerger.mergeFiles(files.toList) + + val raw = Source.fromFile(mergedFile).toArray + raw should equal(raw.sorted) + + println("") + println("merged file below") + printFile(mergedFile) + + //clean up + files.foreach(_.delete()) + mergedFile.delete() + + } + + def printFile(file: File): Unit = { + val source = Source.fromFile(file) + source.getLines().foreach(println) + } + +} From 23bceca7c8b5cc6e52305083240c8827fc6d5626 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 9 Jan 2019 21:56:15 +0800 Subject: [PATCH 13/19] apply idea suggestion --- scala/src/main/scala/ch29_heap_solutions/FileMerger.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala b/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala index 872ca1c..076187a 100644 --- a/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala +++ b/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala @@ -19,7 +19,7 @@ object FileMerger { val output = File.createTempFile("merged-file", ".txt") val writer = new BufferedWriter(new FileWriter(output)) //init small top heap - val priorityQueue = new mutable.PriorityQueue[Tuple2[Char, Source]]()(Ordering.by((_: (Char, Source))._1).reverse) + val priorityQueue = new mutable.PriorityQueue[(Char, Source)]()(Ordering.by((_: (Char, Source))._1).reverse) val sources = smallFiles.toArray.map(smallFile => Source.fromFile(smallFile)) //init fill the priority queue from each file sources.foreach(source => priorityQueue.enqueue(Tuple2(source.next(), source))) From 66857c1fbcf5611306c1b1b47f785db30c965842 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Thu, 10 Jan 2019 12:26:57 +0800 Subject: [PATCH 14/19] fix FileMerge logic issue --- scala/src/main/scala/ch29_heap_solutions/FileMerger.scala | 6 +++--- .../src/test/scala/ch29_heap_solutions/FileMergerTest.scala | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala b/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala index 076187a..a69fd4f 100644 --- a/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala +++ b/scala/src/main/scala/ch29_heap_solutions/FileMerger.scala @@ -22,7 +22,7 @@ object FileMerger { val priorityQueue = new mutable.PriorityQueue[(Char, Source)]()(Ordering.by((_: (Char, Source))._1).reverse) val sources = smallFiles.toArray.map(smallFile => Source.fromFile(smallFile)) //init fill the priority queue from each file - sources.foreach(source => priorityQueue.enqueue(Tuple2(source.next(), source))) + sources.foreach(source => priorityQueue.enqueue((source.next(), source))) breakable { while (true) { @@ -31,10 +31,10 @@ object FileMerger { val source = next._2 writer.append(output) if (source.hasNext) { - priorityQueue.enqueue(Tuple2(source.next(), source)) + priorityQueue.enqueue((source.next(), source)) } //determine the end of merge - if (sources.forall(!_.hasNext)) { + if (sources.forall(!_.hasNext) && priorityQueue.isEmpty) { break } } diff --git a/scala/src/test/scala/ch29_heap_solutions/FileMergerTest.scala b/scala/src/test/scala/ch29_heap_solutions/FileMergerTest.scala index 4bc24cb..b5de3f0 100644 --- a/scala/src/test/scala/ch29_heap_solutions/FileMergerTest.scala +++ b/scala/src/test/scala/ch29_heap_solutions/FileMergerTest.scala @@ -33,6 +33,7 @@ class FileMergerTest extends FlatSpec with Matchers { val raw = Source.fromFile(mergedFile).toArray raw should equal(raw.sorted) + raw.length should equal(num * contentCount) println("") println("merged file below") From ab9f58704c883e28fe1567cc55d52fe80d9a016f Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Thu, 10 Jan 2019 13:35:55 +0800 Subject: [PATCH 15/19] impl top K items --- .../ch29_heap_solutions/TopKItemsKeeper.scala | 30 +++++++++++++++++++ .../TopKItemsKeeperTest.scala | 25 ++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 scala/src/main/scala/ch29_heap_solutions/TopKItemsKeeper.scala create mode 100644 scala/src/test/scala/ch29_heap_solutions/TopKItemsKeeperTest.scala diff --git a/scala/src/main/scala/ch29_heap_solutions/TopKItemsKeeper.scala b/scala/src/main/scala/ch29_heap_solutions/TopKItemsKeeper.scala new file mode 100644 index 0000000..88eba56 --- /dev/null +++ b/scala/src/main/scala/ch29_heap_solutions/TopKItemsKeeper.scala @@ -0,0 +1,30 @@ +package ch29_heap_solutions + +import scala.collection.mutable + +/** + * keep the top k items in the the class + */ +class TopKItemsKeeper(val itemsToKeepCount: Int) { + + + //have a smallest value top heap + val queue = new mutable.PriorityQueue[Int]()(scala.math.Ordering.Int.reverse) + + def put(item: Int): Unit = { + if (queue.length < itemsToKeepCount) { + queue += item + return + } + + //queue already have the k items + if (item.compareTo(queue.head) > 0) { + queue.dequeue() + queue += item + } + } + + def get(): List[Int] = { + queue.clone().dequeueAll + } +} diff --git a/scala/src/test/scala/ch29_heap_solutions/TopKItemsKeeperTest.scala b/scala/src/test/scala/ch29_heap_solutions/TopKItemsKeeperTest.scala new file mode 100644 index 0000000..b3dd0c9 --- /dev/null +++ b/scala/src/test/scala/ch29_heap_solutions/TopKItemsKeeperTest.scala @@ -0,0 +1,25 @@ +package ch29_heap_solutions + +import org.scalatest.{FlatSpec, Matchers} + +import scala.util.Random + +class TopKItemsKeeperTest extends FlatSpec with Matchers { + + behavior of "TopKItemsKeeperTest" + + it should "put and get top K from the keeper" in { + val length = 50 + val k = 5 + val topKItemsKeeper = new TopKItemsKeeper(k) + val nums = new Array[Int](length) + for (i <- Range(0, length)) { + nums(i) = Random.nextInt + } + + nums.foreach(topKItemsKeeper.put) + val ordering = scala.math.Ordering.Int.reverse + topKItemsKeeper.get().toArray.sorted(ordering) should equal(nums.sorted(ordering).slice(0, k)) + } + +} From 42ecf5c1583bc5f810803428ab56888205c6d266 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Thu, 10 Jan 2019 15:56:15 +0800 Subject: [PATCH 16/19] get middle number --- .../MiddleNumberKeeper.scala | 42 +++++++++++++++++++ .../MiddleNumberKeeperTest.scala | 28 +++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 scala/src/main/scala/ch29_heap_solutions/MiddleNumberKeeper.scala create mode 100644 scala/src/test/scala/ch29_heap_solutions/MiddleNumberKeeperTest.scala diff --git a/scala/src/main/scala/ch29_heap_solutions/MiddleNumberKeeper.scala b/scala/src/main/scala/ch29_heap_solutions/MiddleNumberKeeper.scala new file mode 100644 index 0000000..1bc243d --- /dev/null +++ b/scala/src/main/scala/ch29_heap_solutions/MiddleNumberKeeper.scala @@ -0,0 +1,42 @@ +package ch29_heap_solutions + +import scala.collection.mutable + +class MiddleNumberKeeper(val percent: Double) { + + def this() = this(0.5) + + val bigTop = new mutable.PriorityQueue[Int]() + val smallTop = new mutable.PriorityQueue[Int]()(scala.math.Ordering.Int.reverse) + + + def put(num: Int): Unit = { + if (smallTop.nonEmpty && num >= smallTop.head) { + smallTop += num + adjustHeap() + return + } + + //for any other scenario, we just put the item to bitTop then adjustHeap + bigTop += num + adjustHeap() + } + + def get(): Option[Int] = { + bigTop.headOption + } + + private[this] def adjustHeap(): Unit = { + val totalLength = smallTop.length + bigTop.length + //deal with bigTop + while (bigTop.length.doubleValue() / totalLength - percent > 0.0001) { + //move item from bigTop to smallTop + smallTop += bigTop.dequeue() + } + + //deal with smallTop + while (smallTop.length.doubleValue() / totalLength - (1.0D - percent) > 0.0001) { + bigTop += smallTop.dequeue() + } + } +} diff --git a/scala/src/test/scala/ch29_heap_solutions/MiddleNumberKeeperTest.scala b/scala/src/test/scala/ch29_heap_solutions/MiddleNumberKeeperTest.scala new file mode 100644 index 0000000..2dd74f9 --- /dev/null +++ b/scala/src/test/scala/ch29_heap_solutions/MiddleNumberKeeperTest.scala @@ -0,0 +1,28 @@ +package ch29_heap_solutions + +import org.scalatest.{FlatSpec, Matchers} + +class MiddleNumberKeeperTest extends FlatSpec with Matchers { + + behavior of "MiddleNumberKeeperTest" + + it should "get middle of the array" in { + val numKeeper = new MiddleNumberKeeper() + for (i <- Range(0, 10)) { + numKeeper.put(i) + } + + numKeeper.get().get should equal(4) + } + + it should "get 90% position of the array" in { + val numKeeper = new MiddleNumberKeeper(0.9) + for (i <- Range(0, 9)) { + numKeeper.put(i) + } + numKeeper.put(9) + + numKeeper.get().get should equal(8) + } + +} From 1ac446f9c8a1ffbb20b0dd173c4653466f06e57b Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Fri, 11 Jan 2019 17:55:51 +0800 Subject: [PATCH 17/19] graph dfs and bfs --- scala/src/main/scala/ch31_graph/Graph.scala | 89 +++++++++++++++++++ scala/src/test/scala/ch28_heap/HeapTest.scala | 14 ++- .../src/test/scala/ch31_graph/GraphTest.scala | 64 +++++++++++++ 3 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 scala/src/main/scala/ch31_graph/Graph.scala create mode 100644 scala/src/test/scala/ch31_graph/GraphTest.scala diff --git a/scala/src/main/scala/ch31_graph/Graph.scala b/scala/src/main/scala/ch31_graph/Graph.scala new file mode 100644 index 0000000..a9f75be --- /dev/null +++ b/scala/src/main/scala/ch31_graph/Graph.scala @@ -0,0 +1,89 @@ +package ch31_graph + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer +import scala.util.control.Breaks._ + +class Graph(vertex: Array[String]) { + + require(vertex.nonEmpty, "nonEmpty vertex required") + val adjacency = new Array[mutable.MutableList[String]](vertex.length) + for (i <- Range(0, vertex.length)) { + adjacency(i) = new mutable.MutableList[String]() + } + + def addEdge(startNode: String, endNode: String): Unit = { + adjacency(vertex.indexOf(startNode)) += endNode + adjacency(vertex.indexOf(endNode)) += startNode + } + + def getEdges(node: String): Array[String] = { + adjacency(vertex.indexOf(node)).toArray + } + + def breathFirstSearch(startNode: String, destNode: String): Option[Array[String]] = { + var result: Option[Array[String]] = None + val queue = new mutable.Queue[String]() + val visited = new mutable.HashSet[String]() + val explored = new ArrayBuffer[String]() + + //put starting node into the queue + queue += startNode + breakable { + while (queue.nonEmpty) { + val node = queue.dequeue() + if (!visited.contains(node)) { + explored += node + visited += node + + if (node.equals(destNode)) { + result = Some(explored.toArray) + break + } + queue ++= adjacency(vertex.indexOf(node)) + } + + } + } + + result + } + + def depthFirstSearch(startNode: String, destNode: String): Option[Array[String]] = { + var found = false + val visited = new mutable.HashSet[String]() + val explored = new ArrayBuffer[String]() + + def _dfs(start: String): Unit = { + if (found) { + return + } + if (!visited.contains(start)) { + visited += start + explored += start + val destsForStart: mutable.MutableList[String] = adjacency(vertex.indexOf(start)) + + breakable { + for (i <- destsForStart.indices) { + val node = destsForStart(i) + if (node.equals(destNode)) { + found = true + if (!explored.contains(node)) { + explored += node + } + break() + } + _dfs(node) + } + } + } + } + + _dfs(startNode) + if (found) { + Some(explored.toArray) + } else { + None + } + } +} diff --git a/scala/src/test/scala/ch28_heap/HeapTest.scala b/scala/src/test/scala/ch28_heap/HeapTest.scala index c6312e9..6cecc53 100644 --- a/scala/src/test/scala/ch28_heap/HeapTest.scala +++ b/scala/src/test/scala/ch28_heap/HeapTest.scala @@ -31,13 +31,11 @@ class HeapTest extends FlatSpec with Matchers { heap.removeMax() should equal(27) } - it should "sort array" in { - it should "build heap from array - top down" in { - val nums = Array(33, 27, 21, 16, 13, 15, 19, 5, 6, 7, 8, 1, 2, 12) - val result = Heap.heapSort(nums) - - result.mkString("") should equal(nums.sorted.mkString("")) - } - } +// it should "sort array" in { +// val nums = Array(33, 27, 21, 16, 13, 15, 19, 5, 6, 7, 8, 1, 2, 12) +// val result = Heap.heapSort(nums) +// +// result.mkString("") should equal(nums.sorted.mkString("")) +// } } diff --git a/scala/src/test/scala/ch31_graph/GraphTest.scala b/scala/src/test/scala/ch31_graph/GraphTest.scala new file mode 100644 index 0000000..7dfc757 --- /dev/null +++ b/scala/src/test/scala/ch31_graph/GraphTest.scala @@ -0,0 +1,64 @@ +package ch31_graph + +import org.scalatest.{FlatSpec, Matchers} + +class GraphTest extends FlatSpec with Matchers { + + /* + 0 - 1 - 2 + | | | + 3 - 4 - 5 + | | + 6 - 7 + */ + + behavior of "GraphTest" + + def initGraph: Graph = { + val num = 8 + val vertex = new Array[String](num) + for (i <- Range(0, num)) { + vertex(i) = i.toString + } + val graph = new Graph(vertex) + + graph.addEdge("0", "1") + graph.addEdge("1", "2") + graph.addEdge("0", "3") + graph.addEdge("1", "4") + graph.addEdge("2", "5") + graph.addEdge("3", "4") + graph.addEdge("4", "5") + graph.addEdge("4", "6") + graph.addEdge("5", "7") + graph.addEdge("6", "7") + graph + } + + it should "construct the graph" in { + val graph: Graph = initGraph + + graph.getEdges("0").sorted should equal(Array("1", "3")) + graph.getEdges("1").sorted should equal(Array("0", "2", "4")) + graph.getEdges("2").sorted should equal(Array("1", "5")) + graph.getEdges("3").sorted should equal(Array("0", "4")) + graph.getEdges("4").sorted should equal(Array("1", "3", "5", "6")) + graph.getEdges("5").sorted should equal(Array("2", "4", "7")) + graph.getEdges("6").sorted should equal(Array("4", "7")) + graph.getEdges("7").sorted should equal(Array("5", "6")) + } + + it should "do breath first search in graph" in { + val graph: Graph = initGraph + graph.breathFirstSearch("0", "4").get should equal(Array("0", "1", "3", "2", "4")) + graph.breathFirstSearch("1", "5").get should equal(Array("1", "0", "2", "4", "3", "5")) + assert(graph.breathFirstSearch("1", "8").isEmpty) + } + + it should "do depth first search in graph" in { + val graph: Graph = initGraph + graph.depthFirstSearch("0", "4").get should equal(Array("0", "1", "2", "5", "4")) + graph.depthFirstSearch("1", "5").get should equal(Array("1", "0", "3", "4", "5")) + assert(graph.depthFirstSearch("1", "8").isEmpty) + } +} From b36b6c759e9269b1e7eda2fbfe1af8be3b3eeb77 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Sat, 12 Jan 2019 20:45:41 +0800 Subject: [PATCH 18/19] fix heap sort algo --- scala/src/main/scala/ch28_heap/Heap.scala | 4 ++-- scala/src/test/scala/ch28_heap/HeapTest.scala | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scala/src/main/scala/ch28_heap/Heap.scala b/scala/src/main/scala/ch28_heap/Heap.scala index 6bbbd6e..f5f43b6 100644 --- a/scala/src/main/scala/ch28_heap/Heap.scala +++ b/scala/src/main/scala/ch28_heap/Heap.scala @@ -47,9 +47,9 @@ class Heap(val capacity: Int, var elementCount: Int = 0) { def removeMax(): Int = { require(elementCount > 0, "heap is empty") val result = array(1) - elementCount -= 1 array(1) = array(elementCount) - heapifyTopDown(1, elementCount - 1) + elementCount -= 1 + heapifyTopDown(1, elementCount) result } diff --git a/scala/src/test/scala/ch28_heap/HeapTest.scala b/scala/src/test/scala/ch28_heap/HeapTest.scala index 6cecc53..3e9051c 100644 --- a/scala/src/test/scala/ch28_heap/HeapTest.scala +++ b/scala/src/test/scala/ch28_heap/HeapTest.scala @@ -31,11 +31,11 @@ class HeapTest extends FlatSpec with Matchers { heap.removeMax() should equal(27) } -// it should "sort array" in { -// val nums = Array(33, 27, 21, 16, 13, 15, 19, 5, 6, 7, 8, 1, 2, 12) -// val result = Heap.heapSort(nums) -// -// result.mkString("") should equal(nums.sorted.mkString("")) -// } + it should "sort array" in { + val nums = Array(33, 27, 21, 16, 13, 15, 19, 5, 6, 7, 8, 1, 2, 12) + val result = Heap.heapSort(nums) + + result.mkString("") should equal(nums.sorted.mkString("")) + } } From dc7e5171b1f915fa511bcee11ca93686eea61d5d Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Sun, 13 Jan 2019 14:53:07 +0800 Subject: [PATCH 19/19] BruteForce --- .../main/scala/ch32_matching/BruteForce.scala | 24 +++++++++++++++++++ .../scala/ch32_matching/BruteForceTest.scala | 20 ++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 scala/src/main/scala/ch32_matching/BruteForce.scala create mode 100644 scala/src/test/scala/ch32_matching/BruteForceTest.scala diff --git a/scala/src/main/scala/ch32_matching/BruteForce.scala b/scala/src/main/scala/ch32_matching/BruteForce.scala new file mode 100644 index 0000000..ad61226 --- /dev/null +++ b/scala/src/main/scala/ch32_matching/BruteForce.scala @@ -0,0 +1,24 @@ +package ch32_matching + +import scala.util.control.Breaks._ + +object BruteForce { + + def firstIndexOf(main: Array[Char], sub: Array[Char]): Int = { + + require(main != null, "main array required") + require(sub != null, "sub array required") + require(main.length >= sub.length, "sub array should be small than main array") + var result = -1 + breakable { + for (i <- 0 until (main.length - sub.length)) { + if (main.slice(i, i + sub.length) sameElements sub) { + result = i + break + } + } + } + result + } + +} diff --git a/scala/src/test/scala/ch32_matching/BruteForceTest.scala b/scala/src/test/scala/ch32_matching/BruteForceTest.scala new file mode 100644 index 0000000..44f8700 --- /dev/null +++ b/scala/src/test/scala/ch32_matching/BruteForceTest.scala @@ -0,0 +1,20 @@ +package ch32_matching + +import org.scalatest.{FlatSpec, Matchers} + +import scala.util.Random + +class BruteForceTest extends FlatSpec with Matchers { + + behavior of "BruteForceTest" + + it should "find firstIndexOf a sub string" in { + val random = Random.alphanumeric + val main = random.take(1000).toArray + val index = Random.nextInt(950) + val sub = random.take(1000).toArray.slice(index, index + 50) + + BruteForce.firstIndexOf(main, sub) should equal(index) + } + +}