add priority queue

This commit is contained in:
Raffaele Mignone 2019-04-07 17:51:40 +02:00
parent 4f29c6bfbf
commit 953c8fd239
Signed by: norangebit
GPG Key ID: F5255658CB220573
3 changed files with 683 additions and 0 deletions

View File

@ -0,0 +1,243 @@
/*
* MIT License
*
* Copyright (c) 2019 norangebit
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package it.norangeb.algorithms.datastructures.queue.priority
import arrow.core.None
import arrow.core.Option
import arrow.core.toOption
class BinaryHeap<T> private constructor(
private var array: Array<T?>,
private val shouldExchange: (T, T) -> Boolean
) : PriorityQueue<T> {
private var size: Int = 0
override fun insert(elem: T) {
if (isFull())
resizeArray(array.size * WAY)
array[++size] = elem
pushUp(array, size)
}
override fun pop(): Option<T> {
if (size < 1) return None
val result = array[FIRST_ELEMENT]
exchange(array, FIRST_ELEMENT, size)
array[size--] = null
pullDown(array, FIRST_ELEMENT)
if (isOneQuarterFull())
resizeArray(array.size / WAY)
return result.toOption()
}
private fun print() {
print("|")
array.forEach {
print(" $it |")
}
println()
}
override fun peek(): Option<T> = if (size >= 1)
array[1].toOption()
else
None
override fun isEmpty(): Boolean = size == 0
override fun size(): Int = size
private fun pushUp(array: Array<T?>, k: Int) {
when {
k <= 1 -> return
shouldExchange(
array[k / WAY] ?: return,
array[k] ?: return
) -> {
exchange(array, k / WAY, k)
pushUp(array, k / WAY)
}
else -> return
}
}
private fun pullDown(array: Array<T?>, k: Int) {
var i = k
while (i * WAY <= size) {
val child = i * WAY
when {
array[child + 1] == null -> exchange(array, i, child)
shouldExchange(
array[child] ?: return,
array[child + 1] ?: return
) -> exchange(array, i, child + 1)
else -> exchange(array, i, child)
}
i *= WAY
}
pushUp(array, i)
}
private fun exchange(array: Array<T?>, i: Int, j: Int) {
array[i] = array[j].also {
array[j] = array[i]
}
}
private fun isFull(): Boolean = size + 1 == array.size
private fun isOneQuarterFull(): Boolean {
return size > 1 &&
size + 1 == array.size / 4
}
private fun resizeArray(capacity: Int) {
array = array.copyOf(capacity)
}
companion object : COPriorityQueue {
private const val DEFAULT_CAPACITY = 3
private const val WAY = 2
private const val FIRST_ELEMENT = 1
override fun <C : Comparable<C>> createMaxPriorityQueue(): PriorityQueue<C> {
val array: Array<C?> = arrayOfNulls<Comparable<Any>>(DEFAULT_CAPACITY) as Array<C?>
return BinaryHeap(array) { t1, t2 ->
t1 < t2
}
}
override fun <C : Comparable<C>> createMinPriorityQueue(): PriorityQueue<C> {
val array: Array<C?> = arrayOfNulls<Comparable<Any>>(DEFAULT_CAPACITY) as Array<C?>
return BinaryHeap(array) { t1, t2 ->
t1 > t2
}
}
override fun <T> createMaxPriorityQueue(compare: (T, T) -> Int): PriorityQueue<T> {
val array: Array<T?> = arrayOfNulls<Any>(DEFAULT_CAPACITY) as Array<T?>
return BinaryHeap(array) { t1, t2 ->
compare(t1, t2) < 0
}
}
override fun <T> createMinPriorityQueue(compare: (T, T) -> Int): PriorityQueue<T> {
val array: Array<T?> = arrayOfNulls<Any>(DEFAULT_CAPACITY) as Array<T?>
return BinaryHeap(array) { t1, t2 ->
compare(t1, t2) > 0
}
}
override fun <T, C : Comparable<C>> createMaxPriorityQueue(compareBy: (T) -> C): PriorityQueue<T> {
val array: Array<T?> = arrayOfNulls<Any>(DEFAULT_CAPACITY) as Array<T?>
return BinaryHeap(array) { t1, t2 ->
compareBy(t1) < compareBy(t2)
}
}
override fun <T, C : Comparable<C>> createMinPriorityQueue(compareBy: (T) -> C): PriorityQueue<T> {
val array: Array<T?> = arrayOfNulls<Any>(DEFAULT_CAPACITY) as Array<T?>
return BinaryHeap(array) { t1, t2 ->
compareBy(t1) > compareBy(t2)
}
}
override fun <C : Comparable<C>> createMaxPriorityQueueFromArray(array: Array<C>): PriorityQueue<C> {
val heap = BinaryHeap.createMaxPriorityQueue<C>()
array.forEach { heap.insert(it) }
return heap
}
override fun <C : Comparable<C>> createMinPriorityQueueFromArray(array: Array<C>): PriorityQueue<C> {
val heap = BinaryHeap.createMinPriorityQueue<C>()
array.forEach { heap.insert(it) }
return heap
}
override fun <T> createMaxPriorityQueueFromArray(
array: Array<T>,
compare: (T, T) -> Int
): PriorityQueue<T> {
val initArray: Array<T?> = arrayOfNulls<Any>(DEFAULT_CAPACITY) as Array<T?>
val heap = BinaryHeap(initArray) { t1, t2 ->
compare(t1, t2) < 0
}
array.forEach { heap.insert(it) }
return heap
}
override fun <T> createMinPriorityQueueFromArray(
array: Array<T>,
compare: (T, T) -> Int
): PriorityQueue<T> {
val initArray: Array<T?> = arrayOfNulls<Any>(DEFAULT_CAPACITY) as Array<T?>
val heap = BinaryHeap(initArray) { t1, t2 ->
compare(t1, t2) > 0
}
array.forEach { heap.insert(it) }
return heap
}
override fun <T, C : Comparable<C>> createMaxPriorityQueueFromArray(
array: Array<T>,
compareBy: (T) -> C
): PriorityQueue<T> {
val initArray: Array<T?> = arrayOfNulls<Any>(DEFAULT_CAPACITY) as Array<T?>
val heap = BinaryHeap(initArray) { t1, t2 ->
compareBy(t1) < compareBy(t2)
}
array.forEach { heap.insert(it) }
return heap
}
override fun <T, C : Comparable<C>> createMinPriorityQueueFromArray(
array: Array<T>,
compareBy: (T) -> C
): PriorityQueue<T> {
val initArray: Array<T?> = arrayOfNulls<Any>(DEFAULT_CAPACITY) as Array<T?>
val heap = BinaryHeap(initArray) { t1, t2 ->
compareBy(t1) > compareBy(t2)
}
array.forEach { heap.insert(it) }
return heap
}
}
}

View File

@ -0,0 +1,78 @@
/*
* MIT License
*
* Copyright (c) 2019 norangebit
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package it.norangeb.algorithms.datastructures.queue.priority
import arrow.core.Option
interface PriorityQueue<T> {
fun insert(elem: T)
fun pop(): Option<T>
fun peek(): Option<T>
fun isEmpty(): Boolean
fun size(): Int
}
interface COPriorityQueue {
fun <C : Comparable<C>> createMaxPriorityQueue(): PriorityQueue<C>
fun <C : Comparable<C>> createMinPriorityQueue(): PriorityQueue<C>
fun <T> createMaxPriorityQueue(compare: (T, T) -> Int): PriorityQueue<T>
fun <T> createMinPriorityQueue(compare: (T, T) -> Int): PriorityQueue<T>
fun <T, C : Comparable<C>> createMaxPriorityQueue(
compareBy: (T) -> C
): PriorityQueue<T>
fun <T, C : Comparable<C>> createMinPriorityQueue(
compareBy: (T) -> C
): PriorityQueue<T>
fun <C : Comparable<C>> createMaxPriorityQueueFromArray(
array: Array<C>
): PriorityQueue<C>
fun <C : Comparable<C>> createMinPriorityQueueFromArray(
array: Array<C>
): PriorityQueue<C>
fun <T> createMaxPriorityQueueFromArray(
array: Array<T>,
compare: (T, T) -> Int
): PriorityQueue<T>
fun <T> createMinPriorityQueueFromArray(
array: Array<T>,
compare: (T, T) -> Int
): PriorityQueue<T>
fun <T, C : Comparable<C>> createMaxPriorityQueueFromArray(
array: Array<T>,
compareBy: (T) -> C
): PriorityQueue<T>
fun <T, C : Comparable<C>> createMinPriorityQueueFromArray(
array: Array<T>,
compareBy: (T) -> C
): PriorityQueue<T>
}

View File

@ -0,0 +1,362 @@
/*
* MIT License
*
* Copyright (c) 2019 norangebit
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package it.norangeb.algorithms.datastructures.queue.priority
import arrow.core.None
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should equal`
import org.junit.jupiter.api.Test
import kotlin.reflect.full.declaredMemberFunctions
import kotlin.reflect.jvm.isAccessible
class BinaryHeapTest {
@Test
fun testExchange() {
val exchange = BinaryHeap::class.declaredMemberFunctions
.find { it.name == "exchange" }
.also { it?.isAccessible = true }
val binaryHeap = BinaryHeap.createMaxPriorityQueue<Int> { _, _ -> -1 }
val array = arrayOf(1, 2)
exchange?.call(binaryHeap, array, 0, 1)
array `should equal` arrayOf(2, 1)
}
@Test
fun testPushUp() {
val pushUp = BinaryHeap::class.declaredMemberFunctions
.find { it.name == "pushUp" }
.also { it?.isAccessible = true }
val binaryHeap = BinaryHeap.createMaxPriorityQueue<Int> { t1, t2 ->
t1.compareTo(t2)
}
val array = arrayOf(Int.MAX_VALUE, 23, 5, 12, 3, 7)
pushUp?.call(binaryHeap, array, 5)
array `should equal` arrayOf(Int.MAX_VALUE, 23, 7, 12, 3, 5)
}
@Test
fun testComparableMax() {
val heap = BinaryHeap.createMaxPriorityQueue<Int>()
heap.insert(25)
heap.insert(5)
heap.insert(15)
heap.insert(12)
heap.pop().map { it `should be equal to` 25 }
heap.pop().map { it `should be equal to` 15 }
heap.size() `should be equal to` 2
heap.insert(1)
heap.insert(13)
heap.peek().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 12 }
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 1 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testComparableMin() {
val heap = BinaryHeap.createMinPriorityQueue<Int>()
heap.insert(25)
heap.insert(5)
heap.insert(12)
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 12 }
heap.insert(15)
heap.insert(1)
heap.insert(13)
heap.peek().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 15 }
heap.pop().map { it `should be equal to` 25 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testCompareMax() {
val heap = BinaryHeap.createMaxPriorityQueue<Int> { t1, t2 -> t1.compareTo(t2) }
heap.insert(15)
heap.insert(12)
heap.insert(5)
heap.insert(25)
heap.pop().map { it `should be equal to` 25 }
heap.pop().map { it `should be equal to` 15 }
heap.insert(13)
heap.insert(1)
heap.peek().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 12 }
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 1 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testCompareMin() {
val heap = BinaryHeap.createMinPriorityQueue<Int> { t1, t2 -> t1.compareTo(t2) }
heap.insert(25)
heap.insert(5)
heap.insert(12)
heap.insert(15)
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 12 }
heap.insert(1)
heap.insert(13)
heap.peek().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 15 }
heap.pop().map { it `should be equal to` 25 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testCompareByMax() {
val heap = BinaryHeap.createMaxPriorityQueue<Int, Int> { it }
heap.insert(15)
heap.insert(25)
heap.insert(12)
heap.pop().map { it `should be equal to` 25 }
heap.pop().map { it `should be equal to` 15 }
heap.insert(1)
heap.insert(5)
heap.insert(13)
heap.peek().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 12 }
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 1 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testCompareByMin() {
val heap = BinaryHeap.createMinPriorityQueue<Int, Int> { it }
heap.insert(12)
heap.insert(25)
heap.insert(5)
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 12 }
heap.insert(13)
heap.insert(15)
heap.insert(1)
heap.peek().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 15 }
heap.pop().map { it `should be equal to` 25 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testComparableArrayMax() {
val array = arrayOf(5, 12)
val heap = BinaryHeap.createMaxPriorityQueueFromArray(array)
heap.insert(25)
heap.insert(15)
heap.pop().map { it `should be equal to` 25 }
heap.pop().map { it `should be equal to` 15 }
heap.insert(1)
heap.insert(13)
heap.peek().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 12 }
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 1 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testComparableArrayMin() {
val array = arrayOf(12, 25)
val heap = BinaryHeap.createMinPriorityQueueFromArray(array)
heap.insert(5)
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 12 }
heap.insert(15)
heap.insert(1)
heap.insert(13)
heap.peek().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 15 }
heap.pop().map { it `should be equal to` 25 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testCompareMaxArray() {
val array = arrayOf(15, 5)
val heap = BinaryHeap.createMaxPriorityQueueFromArray(array) { t1, t2 ->
t1.compareTo(t2)
}
heap.insert(12)
heap.insert(25)
heap.pop().map { it `should be equal to` 25 }
heap.pop().map { it `should be equal to` 15 }
heap.insert(13)
heap.insert(1)
heap.peek().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 12 }
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 1 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testCompareMinArray() {
val array = arrayOf(15, 12)
val heap = BinaryHeap.createMinPriorityQueueFromArray(array) { t1, t2 ->
t1.compareTo(t2)
}
heap.insert(25)
heap.insert(5)
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 12 }
heap.insert(1)
heap.insert(13)
heap.peek().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 15 }
heap.pop().map { it `should be equal to` 25 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testCompareByMaxArray() {
val array = arrayOf(12)
val heap = BinaryHeap.createMaxPriorityQueueFromArray<Int, Int>(array) { it }
heap.insert(15)
heap.insert(25)
heap.pop().map { it `should be equal to` 25 }
heap.pop().map { it `should be equal to` 15 }
heap.insert(1)
heap.insert(5)
heap.insert(13)
heap.peek().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 12 }
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 1 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testCompareByMinArray() {
val array = arrayOf(5, 12)
val heap = BinaryHeap.createMinPriorityQueueFromArray<Int, Int>(array) { it }
heap.insert(25)
heap.pop().map { it `should be equal to` 5 }
heap.pop().map { it `should be equal to` 12 }
heap.insert(13)
heap.insert(15)
heap.insert(1)
heap.peek().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 1 }
heap.pop().map { it `should be equal to` 13 }
heap.pop().map { it `should be equal to` 15 }
heap.pop().map { it `should be equal to` 25 }
(heap.pop() is None) `should be equal to` true
}
@Test
fun testResize() {
val heap = BinaryHeap.createMaxPriorityQueue<Int>()
(0 until 1000).forEach { heap.insert(it) }
repeat(1010) { heap.pop() }
heap.size() `should be equal to` 0
heap.insert(10)
heap.insert(11)
heap.pop().map { it `should be equal to` 11 }
heap.pop().map { it `should be equal to` 10 }
}
}