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 floor(key: K): Option<K>
fun ceiling(key: K): Option<K> fun ceiling(key: K): Option<K>
fun select(pos: Int): Option<K> fun select(pos: Int): Option<K>
fun rank(key: K): Int
fun <R> preOrder(transform: (K) -> R) fun <R> preOrder(transform: (K) -> R)
fun <R> inOrder(transform: (K) -> R) fun <R> inOrder(transform: (K) -> R)
fun <R> postOrder(transform: (K) -> R) fun <R> postOrder(transform: (K) -> R)

View File

@ -25,10 +25,7 @@
package it.norangeb.algorithms.datastructures.dictionary package it.norangeb.algorithms.datastructures.dictionary
import arrow.core.None import arrow.core.*
import arrow.core.Option
import arrow.core.Some
import arrow.core.toOption
class ImmutableBST<K : Comparable<K>, V> : OrderedDictionary<K, V> { class ImmutableBST<K : Comparable<K>, V> : OrderedDictionary<K, V> {
private var root: Option<Node<K, V>> = None 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> { override fun rank(key: K): Int = rank(root, key)
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
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> { private fun floorRightIfPossible(
TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 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) 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 arrow.core.Some
import org.amshove.kluent.`should be equal to` import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should be` import org.amshove.kluent.`should be`
import org.amshove.kluent.should
import org.amshove.kluent.shouldEqual import org.amshove.kluent.shouldEqual
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -39,11 +38,12 @@ class ImmutableBSTTest {
@Test @Test
fun test() { fun test() {
val orderedMap: OrderedDictionary<String, Int> = ImmutableBST() val orderedMap: OrderedDictionary<String, Int> = ImmutableBST()
orderedMap.isEmpty() `should be` true orderedMap.isEmpty() `should be` true
orderedMap.size() `should be equal to` 0 orderedMap.size() `should be equal to` 0
orderedMap.contains("UNO") `should be` false orderedMap.contains("UNO") `should be` false
orderedMap.max() `should be` None orderedMap.max() shouldEqual None
orderedMap.min() `should be` None orderedMap.min() shouldEqual None
orderedMap["QUATTRO"] = 4 orderedMap["QUATTRO"] = 4
orderedMap["UNO"] = 0 orderedMap["UNO"] = 0
@ -54,13 +54,13 @@ class ImmutableBSTTest {
orderedMap["UNO"] = 1 orderedMap["UNO"] = 1
orderedMap.size() `should be equal to` 3 orderedMap.size() `should be equal to` 3
orderedMap["UNO"] should { this == Some(1) } orderedMap["UNO"] shouldEqual Some(1)
orderedMap["DUE"] = 2 orderedMap["DUE"] = 2
orderedMap["DUE"] should { this == Some(2) } orderedMap["DUE"] shouldEqual Some(2)
orderedMap.max() should { this == Some("UNO") } orderedMap.max() shouldEqual Some("UNO")
orderedMap.min() should { this == Some("DUE") } orderedMap.min() shouldEqual Some("DUE")
} }
@Test @Test
@ -88,13 +88,13 @@ class ImmutableBSTTest {
orderedMap.delete(1) orderedMap.delete(1)
orderedMap.size() `should be equal to` 8 orderedMap.size() `should be equal to` 8
orderedMap.min() should { this == Some(2) } orderedMap.min() shouldEqual Some(2)
//delete node with only right child //delete node with only right child
orderedMap.delete(2) orderedMap.delete(2)
orderedMap.size() `should be equal to` 7 orderedMap.size() `should be equal to` 7
orderedMap.min() should { this == Some(3) } orderedMap.min() shouldEqual Some(3)
//delete node with two child //delete node with two child
orderedMap.delete(10) orderedMap.delete(10)
@ -106,23 +106,27 @@ class ImmutableBSTTest {
orderedMap.delete(11) orderedMap.delete(11)
orderedMap.size() `should be equal to` 4 orderedMap.size() `should be equal to` 4
orderedMap.max() should { this == Some(8) } orderedMap.max() shouldEqual Some(8)
} }
@Test @Test
fun testOrderedOperation() { fun testRanAndSelect() {
val orderedMap: OrderedDictionary<Int, Int> = ImmutableBST() 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[9] = 9
orderedMap[4] = 4 orderedMap[4] = 4
orderedMap[14] = 14 orderedMap[14] = 14
orderedMap.select(0) should { this == Some(4) } orderedMap.rank(5) `should be equal to` 1
orderedMap.select(1) should { this == Some(9) } orderedMap.rank(20) `should be equal to` 3
orderedMap.select(2) should { this == Some(14) } orderedMap.rank(3) `should be equal to` 0
orderedMap.select(3) `should be` None 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[13] = 13
orderedMap[15] = 15 orderedMap[15] = 15
@ -145,36 +149,63 @@ class ImmutableBSTTest {
orderedMap[7] = 7 orderedMap[7] = 7
orderedMap[8] = 8 orderedMap[8] = 8
orderedMap.select(-1) `should be` None orderedMap.select(-1) shouldEqual None
orderedMap.select(0) should { this == Some(0) } orderedMap.select(0) shouldEqual Some(0)
orderedMap.select(1) should { this == Some(1) } orderedMap.select(1) shouldEqual Some(1)
orderedMap.select(5) should { this == Some(5) } orderedMap.select(5) shouldEqual Some(5)
orderedMap.select(8) should { this == Some(8) } orderedMap.select(8) shouldEqual Some(8)
orderedMap.select(9) should { this == Some(9) } orderedMap.select(9) shouldEqual Some(9)
orderedMap.select(10) should { this == Some(10) } orderedMap.select(10) shouldEqual Some(10)
orderedMap.select(14) should { this == Some(14) } orderedMap.select(14) shouldEqual Some(14)
orderedMap.select(17) should { this == Some(17) } orderedMap.select(17) shouldEqual Some(17)
orderedMap.select(18) should { this == Some(18) } orderedMap.select(18) shouldEqual Some(18)
orderedMap.select(19) `should be` None orderedMap.select(19) shouldEqual None
println(orderedMap.select(19))
val orderList = ArrayList<Int>() val orderList = ArrayList<Int>()
orderedMap.inOrder { orderList.add(it) } orderedMap.inOrder { orderList.add(it) }
orderList shouldEqual listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, orderList shouldEqual listOf(
13, 14, 15, 16, 17, 18) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18
)
val postOrderList = ArrayList<Int>() val postOrderList = ArrayList<Int>()
orderedMap.postOrder { postOrderList.add(it) } 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, postOrderList shouldEqual listOf(
14, 9) 0, 1, 2, 3, 8, 7, 6, 5, 4, 10, 11, 12,
13, 18, 17, 16, 15, 14, 9
)
val preOrderList = ArrayList<Int>() val preOrderList = ArrayList<Int>()
orderedMap.preOrder { preOrderList.add(it) } 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, preOrderList shouldEqual listOf(
17, 18) 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')
} }
} }