commit
04d8cdb6bb
61
scala/src/main/scala/ch23_binary_tree/BinaryTree.scala
Normal file
61
scala/src/main/scala/ch23_binary_tree/BinaryTree.scala
Normal file
@ -0,0 +1,61 @@
|
||||
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] {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
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
|
||||
}
|
||||
|
||||
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 == p) {
|
||||
parentNode.left = child
|
||||
} else if (parentNode.right == p) {
|
||||
parentNode.right = child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def height(): Int = {
|
||||
_height(root)
|
||||
}
|
||||
|
||||
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(_height(node.left), _height(node.right)) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
95
scala/src/main/scala/ch28_heap/Heap.scala
Normal file
95
scala/src/main/scala/ch28_heap/Heap.scala
Normal file
@ -0,0 +1,95 @@
|
||||
package ch28_heap
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
array(1) = array(elementCount)
|
||||
elementCount -= 1
|
||||
heapifyTopDown(1, elementCount)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
46
scala/src/main/scala/ch29_heap_solutions/FileMerger.scala
Normal file
46
scala/src/main/scala/ch29_heap_solutions/FileMerger.scala
Normal file
@ -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[(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((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((source.next(), source))
|
||||
}
|
||||
//determine the end of merge
|
||||
if (sources.forall(!_.hasNext) && priorityQueue.isEmpty) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.close()
|
||||
output
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
89
scala/src/main/scala/ch31_graph/Graph.scala
Normal file
89
scala/src/main/scala/ch31_graph/Graph.scala
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
24
scala/src/main/scala/ch32_matching/BruteForce.scala
Normal file
24
scala/src/main/scala/ch32_matching/BruteForce.scala
Normal file
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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")
|
||||
|
50
scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala
Normal file
50
scala/src/test/scala/ch23_binary_tree/BinaryTreeTest.scala
Normal file
@ -0,0 +1,50 @@
|
||||
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")
|
||||
}
|
||||
|
||||
it should "levelOrder" in {
|
||||
tree.levelOrder(root) should equal("ABCDEFG")
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
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)
|
||||
}
|
||||
|
||||
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(""))
|
||||
}
|
||||
|
||||
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 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 height of a tree -3" in {
|
||||
val tree = new BinarySearchTree(None)
|
||||
val nums = Array(33).sorted
|
||||
nums.foreach(tree.insert)
|
||||
tree.height() should equal(1)
|
||||
}
|
||||
|
||||
}
|
41
scala/src/test/scala/ch28_heap/HeapTest.scala
Normal file
41
scala/src/test/scala/ch28_heap/HeapTest.scala
Normal file
@ -0,0 +1,41 @@
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
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(""))
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
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)
|
||||
raw.length should equal(num * contentCount)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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))
|
||||
}
|
||||
|
||||
}
|
64
scala/src/test/scala/ch31_graph/GraphTest.scala
Normal file
64
scala/src/test/scala/ch31_graph/GraphTest.scala
Normal file
@ -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)
|
||||
}
|
||||
}
|
20
scala/src/test/scala/ch32_matching/BruteForceTest.scala
Normal file
20
scala/src/test/scala/ch32_matching/BruteForceTest.scala
Normal file
@ -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)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user