1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-24 11:57:59 +01:00

Implement PairPriorityQueue wrapper

This commit is contained in:
Heiko Schaefer 2023-06-26 14:51:45 +02:00
parent c4214ad2dc
commit 14bbb72692
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
2 changed files with 183 additions and 0 deletions

View file

@ -0,0 +1,41 @@
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 pq: 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 = pq.find { it.first == key }) {
null -> pq.add(Pair(key, value)) // Add as a new element
else -> {
// If the new value is bigger: replace the element
if (value > element.second) {
pq.remove(element)
pq.add(Pair(key, value))
}
}
}
}
fun pop(): Pair<K, V>? = pq.poll()
}

View file

@ -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);
}
}