aboutsummaryrefslogtreecommitdiff
path: root/challenge-018
diff options
context:
space:
mode:
authorJörg Sommrey <28217714+jo-37@users.noreply.github.com>2023-03-16 10:30:36 +0100
committerJörg Sommrey <28217714+jo-37@users.noreply.github.com>2023-03-23 18:03:41 +0100
commit184d93d16b5835cc10dc3aefa14f7fbef06fc436 (patch)
tree0953ef836c09f81a53bd29ca898d706762d36562 /challenge-018
parentcd4218ca053714a7020c0b0b6a141488d6f7c533 (diff)
downloadperlweeklychallenge-club-184d93d16b5835cc10dc3aefa14f7fbef06fc436.tar.gz
perlweeklychallenge-club-184d93d16b5835cc10dc3aefa14f7fbef06fc436.tar.bz2
perlweeklychallenge-club-184d93d16b5835cc10dc3aefa14f7fbef06fc436.zip
Challenge 018 task 2
Diffstat (limited to 'challenge-018')
-rwxr-xr-xchallenge-018/jo-37/perl/ch-2.pl80
1 files changed, 80 insertions, 0 deletions
diff --git a/challenge-018/jo-37/perl/ch-2.pl b/challenge-018/jo-37/perl/ch-2.pl
new file mode 100755
index 0000000000..630fb337fb
--- /dev/null
+++ b/challenge-018/jo-37/perl/ch-2.pl
@@ -0,0 +1,80 @@
+#!/usr/bin/perl -s
+
+use v5.16;
+use warnings;
+use Hash::PriorityQueue;
+use experimental qw(signatures postderef);
+
+# Create a new PriorityQueue object.
+my $pq = PriorityQueue->new;
+
+# Populate the queue with random priorities
+$pq->push('1:1', 1);
+$pq->push('1:0', 0);
+$pq->push('2:1', 1);
+$pq->push('2:0', 0);
+$pq->push('1:-1', -1);
+$pq->push('1:3', 3);
+
+# Get the first item.
+say $pq->shift;
+
+# Continue populating.
+$pq->push('1:2', 2);
+$pq->push('3:1', 1);
+
+# Default priority.
+$pq->push('3:0');
+
+# Retrieve all items.
+say $pq->shift while $pq;;
+
+# Can push anything onto the queue.
+$pq->push(undef);
+say "not empty" if $pq;
+say $pq->shift // 'undef';
+
+### Implementation
+
+package PriorityQueue;
+# Implementing the priority queue as a singly linked list of priority
+# nodes. Each node is an array of three elements:
+# - the priority
+# - a reference to an array of items
+# - a reference to the next node.
+# The priority queue itself is represented by a blessed ref to the first
+# node. Lower priorities come first, default is zero.
+
+# Create a new object.
+sub new ($class) {
+ bless \my ($head), $class;
+}
+
+# Instead of is_empty, provide a Boolean value for the object signaling
+# "not empty".
+use overload 'bool' => sub ($self, @) {!!$$self};
+
+# Push one item with given priority onto the queue.
+sub push ($noderef, $item, $prio=0) {
+ # Find the last node with a priority not larger than the given.
+ for (; $$noderef && $$noderef->[0] <= $prio; $noderef = \$$noderef->[2]) {}
+
+ # If there is no node for the given priority:
+ # - Create a new node
+ # - Link the successor of the last found node to this node
+ # - Link the new node to the last found node
+ $$noderef = [$prio, [], $$noderef]
+ if !$$noderef || $$noderef->[0] != $prio;
+
+ # Push the given item onto its corresponding node queue.
+ push $$noderef->[1]->@*, $item;
+}
+
+sub shift ($noderef) {
+ # Pick the first entry from the first node of the priority queue.
+ my $item = shift $$noderef->[1]->@*;
+ # Remove the leading node if it has become empty.
+ $$noderef = $$noderef->[2] if !$$noderef->[1]->@*;
+
+ $item;
+}