Hello! My name is Itsuki Toyota. I’m a web developer in Japan.

In this post, let me introduce Algorithm::MinMaxHeap.

# Introduction

Algorithm::MinMaxHeap is a Perl 6 implementation of double-ended priority queue (i.e. min-max heap).^{1}

Fig.1 shows an example of this data structure:

This data structure has an interesting property, that is, it has both max-heap and min-heap in a single tree.

More precisely, the min-max ordering is maintained in a single tree as the below description:

- values stored at nodes on
**even levels (i.e. min levels)**are**smaller**than or equal to the values stored at their descendants (if any) - values stored at nodes on
**odd levels (i.e. max levels)**are**greater**than or equal to the values stored at their descendants (if any)

# Algorithm::MinMaxHeap Internals

I’ll shortly explain what this double-ended priority queue does internally when some frequently used methods (e.g. insert, pop) are called on.^{2}

They maintain the min-max ordering by the following operations:

## insert($item)

1. Pushes the given item at the first available leaf position.

2. Checks whether it maintains the min-max ordering by traversing the nodes from **the leaf to the root**. If it finds a violating node, it swaps this node with a proper node and continues the checking operation.

## pop-max

1. Extracts the **maximum** value node.

2. Fills the vacant position with the last node of the queue.

3. Checks whether it maintains the min-max ordering by traversing the nodes from **the** **filled position to the leaf**. If it finds a violating node, it swaps this node with a proper node and continues the checking operation.

## pop-min

1. Extracts the **minimum** value node.

2. Fills the vacant position with the last node of the queue.

3. Checks whether it maintains the min-max ordering by traversing the nodes from **the** **filled position to the leaf**. If it finds a violating node, it swaps this node with a proper node and continues the checking operation.

# Let’s try !

Then let me illustrate how to use Algorithm::MinMaxHeap.

## Example 1

The first example is the simplest one.

**Source:**

use Algorithm::MinMaxHeap; my $queue = Algorithm::MinMaxHeap[Int].new; # (#1) my Int @items = (^10).pick(*); @items.say; # [1 2 6 4 5 9 0 3 7 8] $queue.insert($_) for @items; # (#2) $queue.pop-max.say; # 9 (#3)

In this example, `Algorithm::MinMaxHeap[Int].new`

creates a queue object, where all of its nodes are type `Int`

. (#1)

`$queue.insert($_) for @items`

inserts the numbers in the list. (#2)

`$queue.pop-max`

pops a node which stores the maximum value. (#3)

## Example 2

The second example defines user-defined type constraints using subset:

**Source (chimera.p6):**

use Algorithm::MinMaxHeap; my subset ChimeraRat of Cool where Num|Rat; # (#1) my $queue = Algorithm::MinMaxHeap[ChimeraRat].new; $queue.insert(10e0); # ok $queue.insert(1/10); # ok $queue.insert(10); # die # (#2)

**Output:**

$ perl6 chimera.p6 Type check failed in assignment to @!nodes; expected ChimeraRat but got Int (10) in method insert at /home/itoyota/.rakudobrew/moar-nom/install/share/perl6/site/sources/240192C19BBAACD01AB9686EE53F67BC530F8545 (Algorithm::MinMaxHeap) line 12 in block at chimera.p6 line 8

In this example, subset `ChimeraRat`

is a `Cool`

, but only allows `Num`

or `Rat`

. (#1)

Therefore, when you insert `10`

to the queue, it returns the error message and die.

It’s because `10`

is a `Int`

object. (#2)

## Example 3

The third example inserts user-defined classes to the queue.

**Source (class.p6):**

use Algorithm::MinMaxHeap; my class State { also does Algorithm::MinMaxHeap::Comparable[State]; # (#1) has DateTime $.time; has $.payload; submethod BUILD(:$!time, :$!payload) { } method compare-to(State $s) { # (#2) if $!time == $s.time { return Order::Same; } if $!time > $s.time { return Order::More; } if $!time < $s.time { return Order::Less; } } } my @items; @items.push(State.new(time => DateTime.new(:year(1900), :month(6)), payload => "Rola")); @items.push(State.new(time => DateTime.new(:year(-300), :month(3)), payload => "Taro")); @items.push(State.new(time => DateTime.new(:year(1963), :month(12)), payload => "Hanako")); @items.push(State.new(time => DateTime.new(:year(2020), :month(6)), payload => "Jack")); my Algorithm::MinMaxHeap[Algorithm::MinMaxHeap::Comparable] $queue .= new; $queue.insert($_) for @items; $queue.pop-max.say until $queue.is-empty;

**Output:**

`$ perl6 class.p6`

`State.new(time => DateTime.new(2020,6,1,0,0,0), payload => "Jack")`

`State.new(time => DateTime.new(1963,12,1,0,0,0), payload => "Hanako")`

`State.new(time => DateTime.new(1900,6,1,0,0,0), payload => "Rola")`

`State.new(time => DateTime.new(-300,3,1,0,0,0), payload => "Taro")`

In this example, the class `State`

does the role `Algorithm::MinMaxHeap::Comparable[State]`

, where `Algorithm::MinMaxHeap::Comparable[State]`

defines the stub method `compare-to`

as:

`method compare-to(State) returns Order:D { ... };`

(#1)

Therefore, in this case, the `State`

class must define a method `compare-to`

so that it accepts a `State`

object and returns an `Order:D`

object. (#2)

# Footnote

^{1}*Atkinson, Michael D., et al. “Min-max heaps and generalized priority queues.” Communications of the ACM 29.10 (1986): 996-1000.*^{2}For more exact information, please read the above paper.

Thank you for reading my post !