add some operation to BST
continuous-integration/drone/push Build is passing Details

- add rank
- implement floor
- implement ceiling
This commit is contained in:
Raffaele Mignone 2019-04-19 18:17:29 +02:00
parent 95c2f8c02a
commit 53fd1f9caa
Signed by: norangebit
GPG Key ID: F5255658CB220573
3 changed files with 119 additions and 43 deletions

View File

@ -42,6 +42,7 @@ interface OrderedDictionary<K : Comparable<K>, V> : Dictionary<K, V> {
fun floor(key: K): Option<K>
fun ceiling(key: K): Option<K>
fun select(pos: Int): Option<K>
fun rank(key: K): Int
fun <R> preOrder(transform: (K) -> R)
fun <R> inOrder(transform: (K) -> R)
fun <R> postOrder(transform: (K) -> R)

View File

@ -25,10 +25,7 @@
package it.norangeb.algorithms.datastructures.dictionary
import arrow.core.None
import arrow.core.Option
import arrow.core.Some
import arrow.core.toOption
import arrow.core.*
class ImmutableBST<K : Comparable<K>, V> : OrderedDictionary<K, V> {
private var root: Option<Node<K, V>> = None
@ -141,12 +138,59 @@ class ImmutableBST<K : Comparable<K>, V> : OrderedDictionary<K, V> {
}
}
override fun floor(key: K): Option<K> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
override fun rank(key: K): Int = rank(root, key)
private fun rank(node: Option<Node<K, V>>, key: K): Int = node.map {
when {
it.key == key -> it.child
key < it.key -> rank(it.left, key)
else -> size(it.left) + 1 + rank(it.right, key)
}
}.getOrElse { 0 }
override fun floor(key: K): Option<K> = floor(root, key).map { it.key }
private fun floor(node: Option<Node<K, V>>, key: K): Option<Node<K, V>> {
return node.flatMap {
when {
it.key == key -> node
key < it.key -> floor(it.left, key)
else -> floorRightIfPossible(it, key)
}
}
}
override fun ceiling(key: K): Option<K> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
private fun floorRightIfPossible(
node: Node<K, V>,
key: K
): Option<Node<K, V>> {
val possibleFlor = floor(node.right, key)
return if (possibleFlor is Some)
possibleFlor
else
node.toOption()
}
override fun ceiling(key: K): Option<K> = ceiling(root, key).map { it.key }
private fun ceiling(node: Option<Node<K, V>>, key: K): Option<Node<K, V>> {
return node.flatMap {
when {
it.key == key -> node
key > it.key -> ceiling(it.right, key)
else -> ceilingLeftIfpossible(it, key)
}
}
}
private fun ceilingLeftIfpossible(
node: Node<K, V>,
key: K
): Option<Node<K, V>> {
val possibleCeiling = ceiling(node.left, key)
return if (possibleCeiling is Some)
possibleCeiling
else node.toOption()
}
override fun <R> inOrder(transform: (K) -> R) = inOrder(root, transform)

View File

@ -29,7 +29,6 @@ import arrow.core.None
import arrow.core.Some
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should be`
import org.amshove.kluent.should
import org.amshove.kluent.shouldEqual
import org.junit.jupiter.api.Test
@ -39,11 +38,12 @@ class ImmutableBSTTest {
@Test
fun test() {
val orderedMap: OrderedDictionary<String, Int> = ImmutableBST()
orderedMap.isEmpty() `should be` true
orderedMap.size() `should be equal to` 0
orderedMap.contains("UNO") `should be` false
orderedMap.max() `should be` None
orderedMap.min() `should be` None
orderedMap.max() shouldEqual None
orderedMap.min() shouldEqual None
orderedMap["QUATTRO"] = 4
orderedMap["UNO"] = 0
@ -54,13 +54,13 @@ class ImmutableBSTTest {
orderedMap["UNO"] = 1
orderedMap.size() `should be equal to` 3
orderedMap["UNO"] should { this == Some(1) }
orderedMap["UNO"] shouldEqual Some(1)
orderedMap["DUE"] = 2
orderedMap["DUE"] should { this == Some(2) }
orderedMap.max() should { this == Some("UNO") }
orderedMap.min() should { this == Some("DUE") }
orderedMap["DUE"] shouldEqual Some(2)
orderedMap.max() shouldEqual Some("UNO")
orderedMap.min() shouldEqual Some("DUE")
}
@Test
@ -88,13 +88,13 @@ class ImmutableBSTTest {
orderedMap.delete(1)
orderedMap.size() `should be equal to` 8
orderedMap.min() should { this == Some(2) }
orderedMap.min() shouldEqual Some(2)
//delete node with only right child
orderedMap.delete(2)
orderedMap.size() `should be equal to` 7
orderedMap.min() should { this == Some(3) }
orderedMap.min() shouldEqual Some(3)
//delete node with two child
orderedMap.delete(10)
@ -106,23 +106,27 @@ class ImmutableBSTTest {
orderedMap.delete(11)
orderedMap.size() `should be equal to` 4
orderedMap.max() should { this == Some(8) }
orderedMap.max() shouldEqual Some(8)
}
@Test
fun testOrderedOperation() {
fun testRanAndSelect() {
val orderedMap: OrderedDictionary<Int, Int> = ImmutableBST()
orderedMap.select(0) `should be` None
orderedMap.select(0) shouldEqual None
orderedMap.rank(0) `should be equal to` 0
orderedMap[9] = 9
orderedMap[4] = 4
orderedMap[14] = 14
orderedMap.select(0) should { this == Some(4) }
orderedMap.select(1) should { this == Some(9) }
orderedMap.select(2) should { this == Some(14) }
orderedMap.select(3) `should be` None
orderedMap.rank(5) `should be equal to` 1
orderedMap.rank(20) `should be equal to` 3
orderedMap.rank(3) `should be equal to` 0
orderedMap.select(0) shouldEqual Some(4)
orderedMap.select(1) shouldEqual Some(9)
orderedMap.select(2) shouldEqual Some(14)
orderedMap.select(3) shouldEqual None
orderedMap[13] = 13
orderedMap[15] = 15
@ -145,36 +149,63 @@ class ImmutableBSTTest {
orderedMap[7] = 7
orderedMap[8] = 8
orderedMap.select(-1) `should be` None
orderedMap.select(0) should { this == Some(0) }
orderedMap.select(1) should { this == Some(1) }
orderedMap.select(5) should { this == Some(5) }
orderedMap.select(8) should { this == Some(8) }
orderedMap.select(9) should { this == Some(9) }
orderedMap.select(10) should { this == Some(10) }
orderedMap.select(14) should { this == Some(14) }
orderedMap.select(17) should { this == Some(17) }
orderedMap.select(18) should { this == Some(18) }
orderedMap.select(19) `should be` None
println(orderedMap.select(19))
orderedMap.select(-1) shouldEqual None
orderedMap.select(0) shouldEqual Some(0)
orderedMap.select(1) shouldEqual Some(1)
orderedMap.select(5) shouldEqual Some(5)
orderedMap.select(8) shouldEqual Some(8)
orderedMap.select(9) shouldEqual Some(9)
orderedMap.select(10) shouldEqual Some(10)
orderedMap.select(14) shouldEqual Some(14)
orderedMap.select(17) shouldEqual Some(17)
orderedMap.select(18) shouldEqual Some(18)
orderedMap.select(19) shouldEqual None
val orderList = ArrayList<Int>()
orderedMap.inOrder { orderList.add(it) }
orderList shouldEqual listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18)
orderList shouldEqual listOf(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18
)
val postOrderList = ArrayList<Int>()
orderedMap.postOrder { postOrderList.add(it) }
postOrderList shouldEqual listOf(0, 1, 2, 3, 8, 7, 6, 5, 4, 10, 11, 12, 13, 18, 17, 16, 15,
14, 9)
postOrderList shouldEqual listOf(
0, 1, 2, 3, 8, 7, 6, 5, 4, 10, 11, 12,
13, 18, 17, 16, 15, 14, 9
)
val preOrderList = ArrayList<Int>()
orderedMap.preOrder { preOrderList.add(it) }
preOrderList shouldEqual listOf(9, 4, 3, 2, 1, 0, 5, 6, 7, 8, 14, 13, 12, 11, 10, 15, 16,
17, 18)
preOrderList shouldEqual listOf(
9, 4, 3, 2, 1, 0, 5, 6, 7, 8, 14, 13,
12, 11, 10, 15, 16, 17, 18
)
}
@Test
fun testFloorAndCeiling() {
val orderedMap: OrderedDictionary<Char, Boolean> = ImmutableBST()
orderedMap.floor('Z') shouldEqual None
orderedMap.ceiling('Z') shouldEqual None
orderedMap['S'] = true
orderedMap['X'] = true
orderedMap['E'] = true
orderedMap['A'] = true
orderedMap['C'] = true
orderedMap['R'] = true
orderedMap['H'] = true
orderedMap['M'] = true
orderedMap.floor('G') shouldEqual Some('E')
orderedMap.floor('D') shouldEqual Some('C')
orderedMap.floor('R') shouldEqual Some('R')
orderedMap.ceiling('Q') shouldEqual Some('R')
orderedMap.ceiling('A') shouldEqual Some('A')
}
}