diff options
| author | Jörg Sommrey <28217714+jo-37@users.noreply.github.com> | 2023-03-16 10:30:36 +0100 |
|---|---|---|
| committer | Jörg Sommrey <28217714+jo-37@users.noreply.github.com> | 2023-03-23 18:03:41 +0100 |
| commit | 184d93d16b5835cc10dc3aefa14f7fbef06fc436 (patch) | |
| tree | 0953ef836c09f81a53bd29ca898d706762d36562 /challenge-018 | |
| parent | cd4218ca053714a7020c0b0b6a141488d6f7c533 (diff) | |
| download | perlweeklychallenge-club-184d93d16b5835cc10dc3aefa14f7fbef06fc436.tar.gz perlweeklychallenge-club-184d93d16b5835cc10dc3aefa14f7fbef06fc436.tar.bz2 perlweeklychallenge-club-184d93d16b5835cc10dc3aefa14f7fbef06fc436.zip | |
Challenge 018 task 2
Diffstat (limited to 'challenge-018')
| -rwxr-xr-x | challenge-018/jo-37/perl/ch-2.pl | 80 |
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; +} |
