forked from wangzheng0822/algo
-
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.
Merge pull request wangzheng0822#224 from email2liyang/master
scala trees
- Loading branch information
Showing
17 changed files
with
894 additions
and
0 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
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
148
scala/src/main/scala/ch24_binary_search_tree/BinarySearchTree.scala
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,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 | ||
} | ||
} | ||
} | ||
} | ||
} |
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,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 | ||
} | ||
} |
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,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
42
scala/src/main/scala/ch29_heap_solutions/MiddleNumberKeeper.scala
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,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() | ||
} | ||
} | ||
} |
Oops, something went wrong.