PriorityQueueImpl.mesa
Copyright Ó 1985, 1986, 1989, 1991 by Xerox Corporation. All rights reserved.
Russ Atkinson, February 5, 1985 11:47:32 am PST
Paul Rovner, May 31, 1983 11:53 am
Christian Jacobi, July 22, 1992 2:38 pm PDT
PriorityQueueImpl:
CEDAR
MONITOR
LOCKS pq
USING pq: Ref
EXPORTS PriorityQueue
= BEGIN OPEN PriorityQueue;
The following invariant must be maintained:
for all i in [2..Size]: pred[seq[i/2], seq[i]]
PQempty: PUBLIC ERROR = CODE;
PQover: PUBLIC ERROR = CODE;
IsPriorityQueue:
PUBLIC
PROC [ref:
REF]
RETURNS [
BOOL] = {
... returns TRUE iff the ref resulted from a Create operation
WITH ref
SELECT
FROM
pq: Ref => RETURN [TRUE];
ENDCASE => RETURN [FALSE];
};
Create:
PUBLIC
PROC [pred: SortPred, data:
REF ¬
NIL]
RETURNS [Ref] = {
... creates a new priority queue with given sorting predicate
pq: Ref ¬ NEW[Rep ¬ [pred: pred, data: data, size: 0, seq: NIL]];
RETURN [pq];
};
Predict:
PUBLIC
PROC [size:
INT, pred: SortPred, data:
REF ¬
NIL]
RETURNS [Ref] = {
... is just like create, but also uses a predicted size
pq: Ref ¬ Create[pred, data];
IF size > MaxSize THEN size ¬ MaxSize;
IF size > 0
THEN {
seq: Seq ¬ NEW[SeqRep[size+1]];
pq.seq ¬ seq;
};
pq.size ¬ 0;
RETURN [pq];
Top:
PUBLIC
ENTRY
PROC [pq: Ref]
RETURNS [Item] = {
return the "best" item without modifying the queue
IF pq.size = 0 THEN RETURN WITH ERROR PQempty;
RETURN [pq.seq[1]];
};
Size:
PUBLIC
ENTRY
PROC [pq: Ref]
RETURNS [
INT] = {
return the number of items in the queue
RETURN [pq.size];
};
Empty:
PUBLIC
ENTRY
PROC [pq: Ref]
RETURNS [
BOOL] = {
return true if the queue is empty, false if not
RETURN [pq.size = 0];
};
Insert:
PUBLIC
ENTRY
PROC [pq: Ref, item: Item] = {
... inserts new item into the queue (signal PQover if resulting size goes over MaxSize)
ENABLE UNWIND => NULL;
size: NAT ¬ pq.size; -- figure out new size
a: Seq ¬ pq.seq; -- grab the descriptor
pred: SortPred ¬ pq.pred; -- and the predicate
data: REF ¬ pq.data; -- and the predicate's data
space: NAT ¬ IF a = NIL THEN 0 ELSE a.space;
maxCard: NAT = MaxSize; -- to aid the poor little compiler
overflow check (unfortunately, we can't get more than LAST[NAT] words!)
size ¬ size + 1;
IF size >= MaxSize THEN RETURN WITH ERROR PQover;
Must first check for room in array. If there is not enough room, then allocate new storage, copy, and free the old storage.
IF size >= space
THEN {
seq: Seq ¬ NIL;
IF space = 0 THEN space ¬ 1;
SELECT space
FROM
< 2048 => space ¬ space + space;
< maxCard-1024 => space ¬ space + 1024;
ENDCASE => space ¬ MaxSize;
seq ¬ NEW[SeqRep[space]];
FOR i:
NAT
IN [1..size)
DO
seq[i] ¬ a[i];
ENDLOOP;
pq.seq ¬ a ¬ seq;
};
{
Insert item by shuffling items down until invariant holds (assuming that a[son] will hold item).
son: NAT ¬ size;
dad: NAT ¬ son/2;
WHILE dad > 0
AND pred[item, a[dad], data]
DO
item is better than a[dad], so shuffle a[dad] down
a[son] ¬ a[dad];
son ¬ dad;
dad ¬ son/2;
ENDLOOP;
a[son] ¬ item; -- finally insert the new item
pq.size ¬ size; -- also update the size
};
};
Remove:
PUBLIC
ENTRY
PROC [pq: Ref]
RETURNS [Item] = {
... removes "best" item from queue (signal PQempty if empty)
ENABLE UNWIND => NULL;
size: NAT ¬ pq.size; -- current size of pq
a: Seq ¬ pq.seq; -- desc to real stuff
best: Item ¬ NIL; -- holder for best item
item: Item ¬ NIL; -- holder for moving item
pred: SortPred ¬ pq.pred; -- comparison predicate
data: REF ¬ pq.data; -- and the predicate's data
IF size = 0 THEN RETURN WITH ERROR PQempty;
Remove top item from the array and prepare to move bottom item
best ¬ a[1]; -- remember best item
item ¬ a[size]; -- get moving item
a[size] ¬ NIL;
size ¬ size - 1; -- new size of pq
pq.size ¬ size; -- also update size in pq
IF size = 0 THEN RETURN [best];
Restore the invariant by moving the item down (better items move up)
{
dad: NAT ¬ 1; -- current index for moving item
maxdad: NAT ¬ size / 2; -- highest index for father item
WHILE dad <= maxdad
DO
son: NAT ¬ dad + dad;
sonItem: Item ¬ a[son];
IF son < size
THEN {
must find better of the two sons
nson: NAT ¬ son + 1;
nsonItem: Item ¬ a[nson];
IF pred[nsonItem, sonItem, data]
THEN {
son ¬ nson;
sonItem ¬ nsonItem;
};
};
IF pred[item, sonItem, data] THEN EXIT;
a[dad] ¬ sonItem;
dad ¬ son;
ENDLOOP;
a[dad] ¬ item;
};
Return the saved best item
RETURN [best];
};
Copy:
PUBLIC
ENTRY
PROC [pq: Ref]
RETURNS [Ref] = {
... returns copy of queue
ENABLE UNWIND => NULL;
size: NAT ¬ pq.size;
npq: Ref ¬ Predict[size, pq.pred, pq.data];
src: Seq ¬ pq.seq;
dst: Seq ¬ npq.seq;
FOR i:
NAT
IN [1..size)
DO
dst[i] ¬ src[i];
ENDLOOP;
npq.size ¬ size;
RETURN [npq];
};
END.