Skip to content

Commit

Permalink
Merge pull request wangzheng0822#224 from email2liyang/master
Browse files Browse the repository at this point in the history
scala trees
  • Loading branch information
wangzheng0822 authored Jan 14, 2019
2 parents b974998 + dc7e517 commit 04d8cdb
Show file tree
Hide file tree
Showing 17 changed files with 894 additions and 0 deletions.
61 changes: 61 additions & 0 deletions scala/src/main/scala/ch23_binary_tree/BinaryTree.scala
Original file line number Diff line number Diff line change
@@ -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
}
}
148 changes: 148 additions & 0 deletions scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala
Original file line number Diff line number Diff line change
@@ -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 changes: 95 additions & 0 deletions scala/src/main/scala/ch28_heap/Heap.scala
Original file line number Diff line number Diff line change
@@ -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 changes: 46 additions & 0 deletions scala/src/main/scala/ch29_heap_solutions/FileMerger.scala
Original file line number Diff line number Diff line change
@@ -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
}
}
42 changes: 42 additions & 0 deletions scala/src/main/scala/ch29_heap_solutions/MiddleNumberKeeper.scala
Original file line number Diff line number Diff line change
@@ -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()
}
}
}
Loading

0 comments on commit 04d8cdb

Please sign in to comment.