mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-16 01:12:05 +01:00
Implement PairPriorityQueue wrapper
This commit is contained in:
parent
9515eb0934
commit
cf3843c589
2 changed files with 184 additions and 0 deletions
|
@ -0,0 +1,42 @@
|
||||||
|
package org.pgpainless.wot.dijkstra
|
||||||
|
|
||||||
|
import java.util.PriorityQueue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A de-duplicating max-priority queue for key-value pairs.
|
||||||
|
*
|
||||||
|
* When an element is popped, the queue entry with the *largest value*
|
||||||
|
* is popped (if there are multiple elements with the same max value,
|
||||||
|
* one of them is returned.)
|
||||||
|
*
|
||||||
|
* When inserting an element, if there is already an element with the same
|
||||||
|
* key, the element with the larger value is kept.
|
||||||
|
*/
|
||||||
|
internal class PairPriorityQueue<K, V : Comparable<V>>() {
|
||||||
|
|
||||||
|
// NOTE: This implementation is not optimized for efficient inserts!
|
||||||
|
// - Each insert() involves a linear search by key
|
||||||
|
// - Each insert() sorts eagerly (via j.u.PriorityQueue.add())
|
||||||
|
|
||||||
|
private val internal: PriorityQueue<Pair<K, V>> = PriorityQueue {
|
||||||
|
// Order priority queue entries by value (max first)
|
||||||
|
o1, o2 ->
|
||||||
|
o2.second.compareTo(o1.second)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insert(key: K, value: V) {
|
||||||
|
when (val element = internal.find { it.first == key }) {
|
||||||
|
null -> internal.add(Pair(key, value)) // Add as a new element
|
||||||
|
else -> {
|
||||||
|
// If the new value is bigger: replace the element
|
||||||
|
if (value > element.second) {
|
||||||
|
internal.remove(element)
|
||||||
|
internal.add(Pair(key, value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pop(): Pair<K, V>? = internal.poll()
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
package org.pgpainless.wot.dijkstra
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
// Priority queue tests.
|
||||||
|
|
||||||
|
// Test data from `sequoia-wot:src/priority_queue.rs`.
|
||||||
|
class PriorityQueueTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simple1() {
|
||||||
|
val pq: PairPriorityQueue<Int, Int> = PairPriorityQueue();
|
||||||
|
|
||||||
|
pq.insert(0, 0);
|
||||||
|
pq.insert(1, 1);
|
||||||
|
pq.insert(2, 2);
|
||||||
|
pq.insert(3, 3);
|
||||||
|
pq.insert(4, 4);
|
||||||
|
pq.insert(5, 5);
|
||||||
|
|
||||||
|
assertEquals(pq.pop(), Pair(5, 5));
|
||||||
|
assertEquals(pq.pop(), Pair(4, 4));
|
||||||
|
assertEquals(pq.pop(), Pair(3, 3));
|
||||||
|
assertEquals(pq.pop(), Pair(2, 2));
|
||||||
|
assertEquals(pq.pop(), Pair(1, 1));
|
||||||
|
assertEquals(pq.pop(), Pair(0, 0));
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simple2() {
|
||||||
|
val pq: PairPriorityQueue<Int, Int> = PairPriorityQueue();
|
||||||
|
|
||||||
|
pq.insert(0, 0);
|
||||||
|
pq.insert(1, -1);
|
||||||
|
pq.insert(2, -2);
|
||||||
|
pq.insert(3, -3);
|
||||||
|
pq.insert(4, -4);
|
||||||
|
pq.insert(5, -5);
|
||||||
|
|
||||||
|
assertEquals(pq.pop(), Pair(0, 0));
|
||||||
|
assertEquals(pq.pop(), Pair(1, -1));
|
||||||
|
assertEquals(pq.pop(), Pair(2, -2));
|
||||||
|
assertEquals(pq.pop(), Pair(3, -3));
|
||||||
|
assertEquals(pq.pop(), Pair(4, -4));
|
||||||
|
assertEquals(pq.pop(), Pair(5, -5));
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simple3() {
|
||||||
|
val pq: PairPriorityQueue<Int, Int> = PairPriorityQueue();
|
||||||
|
|
||||||
|
pq.insert(0, 0);
|
||||||
|
pq.insert(1, 1);
|
||||||
|
pq.insert(5, 5);
|
||||||
|
pq.insert(2, 2);
|
||||||
|
pq.insert(4, 4);
|
||||||
|
pq.insert(3, 3);
|
||||||
|
|
||||||
|
assertEquals(pq.pop(), Pair(5, 5));
|
||||||
|
assertEquals(pq.pop(), Pair(4, 4));
|
||||||
|
assertEquals(pq.pop(), Pair(3, 3));
|
||||||
|
assertEquals(pq.pop(), Pair(2, 2));
|
||||||
|
assertEquals(pq.pop(), Pair(1, 1));
|
||||||
|
assertEquals(pq.pop(), Pair(0, 0));
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simple4() {
|
||||||
|
val pq: PairPriorityQueue<Int, Int> = PairPriorityQueue();
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
|
||||||
|
pq.insert(0, 0);
|
||||||
|
pq.insert(0, 0);
|
||||||
|
assertEquals(pq.pop(), Pair(0, 0));
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simple5() {
|
||||||
|
val pq: PairPriorityQueue<Int, Int> = PairPriorityQueue();
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
|
||||||
|
pq.insert(0, 0);
|
||||||
|
pq.insert(0, 0);
|
||||||
|
assertEquals(pq.pop(), Pair(0, 0));
|
||||||
|
pq.insert(0, 0);
|
||||||
|
assertEquals(pq.pop(), Pair(0, 0));
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun duplicates() {
|
||||||
|
val pq: PairPriorityQueue<Int, Int> = PairPriorityQueue();
|
||||||
|
|
||||||
|
// Insert different keys with the same value.
|
||||||
|
for (i in 0 until 20) {
|
||||||
|
pq.insert(i, 0);
|
||||||
|
}
|
||||||
|
// Insert the same keys with their own value. This should
|
||||||
|
// overwrite the old keys.
|
||||||
|
for (i in 0 until 20) {
|
||||||
|
pq.insert(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert different keys with the same value.
|
||||||
|
for (i in 0 until 20) {
|
||||||
|
pq.insert(i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 19 downTo 0) {
|
||||||
|
assertEquals(pq.pop(), Pair(i, i));
|
||||||
|
}
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun insert_pop() {
|
||||||
|
val pq: PairPriorityQueue<Int, Int> = PairPriorityQueue();
|
||||||
|
|
||||||
|
// Insert different keys with the same value.
|
||||||
|
for (i in 0 until 10) {
|
||||||
|
pq.insert(i, 0);
|
||||||
|
}
|
||||||
|
// Insert the same keys with their own value. This should
|
||||||
|
// overwrite the old keys.
|
||||||
|
for (i in 9 downTo 0) {
|
||||||
|
pq.insert(i, i);
|
||||||
|
assertEquals(pq.pop(), Pair(i, i));
|
||||||
|
}
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
assertEquals(pq.pop(), null);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue