-- RightFeaturePQImpl.mesa
-- A generic package to organize items
-- in a priority queue, sorted by increasing order of
-- Val.
-- last modified by E. McCreight, September 28, 1984 10:12 AM
-- written by E. McCreight, February 8, 1982 2:04 PM
DIRECTORY
InlineDefs,
RightFeaturePQ;
RightFeaturePQImpl: PROGRAM
IMPORTS InlineDefs, RightFeaturePQ
EXPORTS RightFeaturePQ SHARES RightFeaturePQ =
BEGIN OPEN RightFeaturePQ;
RightFeaturePQUnderflow: PUBLIC SIGNAL = CODE;
NewRightFeaturePQ: PUBLIC PROCEDURE[zone: UNCOUNTED ZONE,
max: CARDINAL ← 50]
RETURNS[PQHandle] =
BEGIN
p: PQHandle ← zone.NEW[PQObject ← [zone: zone]];
p.s[0] ← zone.NEW[PQSeq[max]];
RETURN[p];
END;
DestroyRightFeaturePQ: PUBLIC PROCEDURE[p: PQHandle]
RETURNS[PQHandle] =
BEGIN
zone: UNCOUNTED ZONE ← p.zone;
FOR i: [0..maxNSeqs) IN [0..p.topSeq) DO zone.FREE[@p.s[i]] ENDLOOP;
zone.FREE[@p];
RETURN[NIL];
END; -- of DestroyRightFeaturePQ
InsertRightFeaturePQ: PUBLIC PROCEDURE[p: PQHandle, item: Item] =
BEGIN
GrowingPQ[p];
CheckPQ[p];
p.size ← p.size+1;
IF p.topSeq=0 THEN
BEGIN
pqs: PQSeqPtr ← p.s[0];
i, j: CARDINAL;
FOR j ← InlineDefs.LowHalf[p.size]-1, i WHILE j>0 DO
i ← (j-1)/2;
IF NOT ValLess[item, pqs[i]] THEN EXIT
ELSE pqs[j] ← pqs[i];
ENDLOOP;
pqs[j] ← item;
END
ELSE
BEGIN
i, j: LONG INTEGER;
FOR j ← p.size-1, i WHILE j>0 DO
i ← (j-1)/2;
IF NOT ValLess[item, GetItem[p, i]] THEN EXIT
ELSE SetItem[p, j, GetItem[p, i]];
ENDLOOP;
SetItem[p, j, item];
END;
CheckPQ[p];
END;
ExtractRightFeaturePQ: PUBLIC PROCEDURE[p: PQHandle]
RETURNS[item: Item] =
BEGIN
result: Item ← p.s[0][0];
ShrinkingPQ[p];
CheckPQ[p];
IF (p.size ← p.size-1)>0 THEN
BEGIN
IF p.topSeq=0 THEN
BEGIN
pqs: PQSeqPtr ← p.s[0];
i, j: CARDINAL;
r: CARDINAL ← InlineDefs.LowHalf[p.size]-1; -- max index
item: Item ← pqs[InlineDefs.LowHalf[p.size]];
FOR i ← 0, j DO
j ← i+i+1;
IF j>r THEN EXIT;
IF j<r AND ValLess[pqs[j+1], pqs[j]] THEN j ← j+1;
IF NOT ValLess[pqs[j], item] THEN EXIT
ELSE pqs[i] ← pqs[j];
ENDLOOP;
pqs[i] ← item;
END
ELSE
BEGIN
i, j: LONG INTEGER;
r: LONG INTEGER ← p.size-1; -- max index
item: Item ← GetItem[p, p.size];
FOR i ← 0, j DO
j ← i+i+1;
IF j>r THEN EXIT;
IF j<r AND ValLess[GetItem[p, j+1], GetItem[p, j]] THEN j ← j+1;
IF NOT ValLess[GetItem[p, j], item] THEN EXIT
ELSE SetItem[p, i, GetItem[p, j]];
ENDLOOP;
SetItem[p, i, item];
END;
END;
CheckPQ[p];
RETURN[result];
END;
MapEqualRightFeaturePQ: PUBLIC PROCEDURE[p: PQHandle,
proc: PROCEDURE[item: Item]] =
BEGIN
pqs: PQSeqPtr ← p.s[0];
stack: ARRAY[1..20) OF LONG INTEGER;
stackTop: [0..20) ← 1;
stack[stackTop] ← 0;
WHILE 0<stackTop DO
i: LONG INTEGER ← stack[stackTop];
item: Item;
IF p.size<=i OR
ValLess[pqs[0], (item ← GetItem[p, i])] THEN
stackTop ← stackTop-1
ELSE
BEGIN
proc[item];
stack[stackTop] ← i+i+1;
stackTop ← stackTop+1;
stack[stackTop] ← i+i+2;
END;
ENDLOOP;
END; -- of MapEqualRightFeaturePQ
DeleteEqualRightFeaturePQ: PUBLIC PROCEDURE[p: PQHandle] =
BEGIN
original: Item ← p.s[0][0];
IF p.topSeq=0 THEN
BEGIN
size: CARDINAL ← InlineDefs.LowHalf[p.size];
pqs: PQSeqPtr ← p.s[0];
WHILE 0<size AND
NOT ValLess[original, pqs[0]] DO
i, j: CARDINAL;
r: CARDINAL ← (size ← size-1); -- max index
item: Item ← pqs[size];
FOR i ← 0, j DO
j ← i+i+1;
IF j>r THEN EXIT;
IF j<r AND ValLess[pqs[j+1], pqs[j]] THEN j ← j+1;
IF NOT ValLess[pqs[j], item] THEN EXIT
ELSE pqs[i] ← pqs[j];
ENDLOOP;
pqs[i] ← item;
ENDLOOP;
p.size ← size+1;
[] ← ShrinkingPQ[p];
p.size ← size;
END
ELSE
WHILE 0<p.size AND NOT ValLess[original, p.s[0][0]] DO
[] ← ExtractRightFeaturePQ[p];
ENDLOOP;
END; -- of DeleteEqualRightFeaturePQ
GrowingPQ: PROCEDURE[p: PQHandle] =
BEGIN
IF p.size>=p.topSeq*maxItemsPerSeq+p.s[p.topSeq].max THEN
BEGIN
IF p.s[p.topSeq].max=maxItemsPerSeq THEN
BEGIN -- new sequence
p.topSeq ← p.topSeq+1;
p.s[p.topSeq] ← p.zone.NEW[PQSeq[maxItemsPerSeq/2]];
END
ELSE
BEGIN -- lengthen existing sequence
oldSeq: PQSeqPtr ← p.s[p.topSeq];
newSeq: PQSeqPtr ←
p.zone.NEW[PQSeq[(IF p.topSeq>0 THEN maxItemsPerSeq ELSE
MIN[maxItemsPerSeq, MAX[50,
InlineDefs.LowHalf[(LONG[15]*p.size)/10]]])]];
FOR i: CARDINAL IN [0..InlineDefs.LowHalf[p.size MOD maxItemsPerSeq]) DO
newSeq[i] ← oldSeq[i];
ENDLOOP;
p.s[p.topSeq] ← newSeq;
p.zone.FREE[@oldSeq];
END;
END;
END;
ShrinkingPQ: PROCEDURE[p: PQHandle] =
BEGIN
WHILE p.size<1 DO SIGNAL RightFeaturePQUnderflow ENDLOOP;
IF p.topSeq>0 THEN
BEGIN
IF p.size < p.topSeq*maxItemsPerSeq-maxItemsPerSeq/2 THEN
BEGIN -- get rid of entire top sequence
END;
END
ELSE
BEGIN
IF MAX[p.size, 50]< p.s[0].max/2 THEN
BEGIN -- shorten the (single) sequence
oldSeq: PQSeqPtr ← p.s[0];
newSeq: PQSeqPtr ←
p.zone.NEW[PQSeq[MAX[
InlineDefs.LowHalf[(LONG[15]*p.size)/10], 50]]];
FOR i: CARDINAL IN [0..InlineDefs.LowHalf[p.size]) DO
newSeq[i] ← oldSeq[i];
ENDLOOP;
p.s[0] ← newSeq;
p.zone.FREE[@oldSeq];
END;
END;
END;
GetItem: PROCEDURE [p: PQHandle, i: LONG INTEGER] RETURNS [item: Item] =
BEGIN
RETURN[p.s[InlineDefs.LowHalf[i/maxItemsPerSeq]][InlineDefs.LowHalf[i MOD maxItemsPerSeq]]];
END;
SetItem: PROCEDURE [p: PQHandle, i: LONG INTEGER, item: Item] =
BEGIN
p.s[InlineDefs.LowHalf[i/maxItemsPerSeq]][InlineDefs.LowHalf[i MOD maxItemsPerSeq]] ← item;
END;
CheckPQ: PROCEDURE[p: PQHandle] = {NULL};
-- or DoCheckPQ[p] for checking
PQDisorder: SIGNAL = CODE;
DoCheckPQ: PROCEDURE[p: PQHandle] =
BEGIN
FOR i: LONG INTEGER IN [0..p.size/2) DO
IF ValLess[GetItem[p, 2*i+1], GetItem[p, i]] OR
((2*i+2<p.size) AND ValLess[GetItem[p, 2*i+2], GetItem[p, i]]) THEN
SIGNAL PQDisorder;
ENDLOOP;
END;
END. -- of RightFeaturePQImpl