201 lines
6.4 KiB
Plaintext
201 lines
6.4 KiB
Plaintext
CLASS AVL;
|
|
BEGIN
|
|
|
|
! AVL TREE ADAPTED FROM JULIENNE WALKER'S PRESENTATION AT ;
|
|
! HTTP://ETERNALLYCONFUZZLED.COM/TUTS/DATASTRUCTURES/JSW_TUT_AVL.ASPX. ;
|
|
! THIS PORT USES SIMILAR INDENTIFIER NAMES. ;
|
|
|
|
! THE KEY INTERFACE MUST BE SUPPORTED BY DATA STORED IN THE AVL TREE. ;
|
|
CLASS KEY;
|
|
VIRTUAL:
|
|
PROCEDURE LESS IS BOOLEAN PROCEDURE LESS (K); REF(KEY) K;;
|
|
PROCEDURE EQUAL IS BOOLEAN PROCEDURE EQUAL(K); REF(KEY) K;;
|
|
BEGIN
|
|
END KEY;
|
|
|
|
! NODE IS A NODE IN AN AVL TREE. ;
|
|
CLASS NODE(DATA); REF(KEY) DATA; ! ANYTHING COMPARABLE WITH LESS AND EQUAL. ;
|
|
BEGIN
|
|
INTEGER BALANCE; ! BALANCE FACTOR ;
|
|
REF(NODE) ARRAY LINK(0:1); ! CHILDREN, INDEXED BY "DIRECTION", 0 OR 1. ;
|
|
END NODE;
|
|
|
|
! A LITTLE READABILITY FUNCTION FOR RETURNING THE OPPOSITE OF A DIRECTION, ;
|
|
! WHERE A DIRECTION IS 0 OR 1. ;
|
|
! WHERE JW WRITES !DIR, THIS CODE HAS OPP(DIR). ;
|
|
INTEGER PROCEDURE OPP(DIR); INTEGER DIR;
|
|
BEGIN
|
|
OPP := 1 - DIR;
|
|
END OPP;
|
|
|
|
! SINGLE ROTATION ;
|
|
REF(NODE) PROCEDURE SINGLE(ROOT, DIR); REF(NODE) ROOT; INTEGER DIR;
|
|
BEGIN
|
|
REF(NODE) SAVE;
|
|
SAVE :- ROOT.LINK(OPP(DIR));
|
|
ROOT.LINK(OPP(DIR)) :- SAVE.LINK(DIR);
|
|
SAVE.LINK(DIR) :- ROOT;
|
|
SINGLE :- SAVE;
|
|
END SINGLE;
|
|
|
|
! DOUBLE ROTATION ;
|
|
REF(NODE) PROCEDURE DOUBLE(ROOT, DIR); REF(NODE) ROOT; INTEGER DIR;
|
|
BEGIN
|
|
REF(NODE) SAVE;
|
|
SAVE :- ROOT.LINK(OPP(DIR)).LINK(DIR);
|
|
|
|
ROOT.LINK(OPP(DIR)).LINK(DIR) :- SAVE.LINK(OPP(DIR));
|
|
SAVE.LINK(OPP(DIR)) :- ROOT.LINK(OPP(DIR));
|
|
ROOT.LINK(OPP(DIR)) :- SAVE;
|
|
|
|
SAVE :- ROOT.LINK(OPP(DIR));
|
|
ROOT.LINK(OPP(DIR)) :- SAVE.LINK(DIR);
|
|
SAVE.LINK(DIR) :- ROOT;
|
|
DOUBLE :- SAVE;
|
|
END DOUBLE;
|
|
|
|
! ADJUST BALANCE FACTORS AFTER DOUBLE ROTATION ;
|
|
PROCEDURE ADJUSTBALANCE(ROOT, DIR, BAL); REF(NODE) ROOT; INTEGER DIR, BAL;
|
|
BEGIN
|
|
REF(NODE) N, NN;
|
|
N :- ROOT.LINK(DIR);
|
|
NN :- N.LINK(OPP(DIR));
|
|
IF NN.BALANCE = 0 THEN BEGIN ROOT.BALANCE := 0; N.BALANCE := 0; END ELSE
|
|
IF NN.BALANCE = BAL THEN BEGIN ROOT.BALANCE := -BAL; N.BALANCE := 0; END
|
|
ELSE BEGIN ROOT.BALANCE := 0; N.BALANCE := BAL; END;
|
|
NN.BALANCE := 0;
|
|
END ADJUSTBALANCE;
|
|
|
|
REF(NODE) PROCEDURE INSERTBALANCE(ROOT, DIR); REF(NODE) ROOT; INTEGER DIR;
|
|
BEGIN REF(NODE) N; INTEGER BAL;
|
|
N :- ROOT.LINK(DIR);
|
|
BAL := 2*DIR - 1;
|
|
IF N.BALANCE = BAL THEN
|
|
BEGIN
|
|
ROOT.BALANCE := 0;
|
|
N.BALANCE := 0;
|
|
INSERTBALANCE :- SINGLE(ROOT, OPP(DIR));
|
|
END ELSE
|
|
BEGIN
|
|
ADJUSTBALANCE(ROOT, DIR, BAL);
|
|
INSERTBALANCE :- DOUBLE(ROOT, OPP(DIR));
|
|
END;
|
|
END INSERTBALANCE;
|
|
|
|
CLASS TUPLE(N,B); REF(NODE) N; BOOLEAN B;;
|
|
|
|
REF(TUPLE) PROCEDURE INSERTR(ROOT, DATA); REF(NODE) ROOT; REF(KEY) DATA;
|
|
BEGIN
|
|
IF ROOT == NONE THEN
|
|
INSERTR :- NEW TUPLE(NEW NODE(DATA), FALSE)
|
|
ELSE
|
|
BEGIN
|
|
REF(TUPLE) T; BOOLEAN DONE; INTEGER DIR;
|
|
DIR := 0;
|
|
IF ROOT.DATA.LESS(DATA) THEN
|
|
DIR := 1;
|
|
T :- INSERTR(ROOT.LINK(DIR), DATA);
|
|
ROOT.LINK(DIR) :- T.N;
|
|
DONE := T.B;
|
|
IF DONE THEN INSERTR :- NEW TUPLE(ROOT, TRUE) ELSE
|
|
BEGIN
|
|
ROOT.BALANCE := ROOT.BALANCE + 2*DIR - 1;
|
|
IF ROOT.BALANCE = 0 THEN
|
|
INSERTR :- NEW TUPLE(ROOT, TRUE) ELSE
|
|
IF ROOT.BALANCE = 1 OR ROOT.BALANCE = -1 THEN
|
|
INSERTR :- NEW TUPLE(ROOT, FALSE)
|
|
ELSE
|
|
INSERTR :- NEW TUPLE(INSERTBALANCE(ROOT, DIR), TRUE);
|
|
END;
|
|
END;
|
|
END INSERTR;
|
|
|
|
! INSERT A NODE INTO THE AVL TREE. ;
|
|
! DATA IS INSERTED EVEN IF OTHER DATA WITH THE SAME KEY ALREADY EXISTS. ;
|
|
PROCEDURE INSERT(TREE, DATA); NAME TREE; REF(NODE) TREE; REF(KEY) DATA;
|
|
BEGIN
|
|
REF(TUPLE) T;
|
|
T :- INSERTR(TREE, DATA);
|
|
TREE :- T.N;
|
|
END INSERT;
|
|
|
|
REF(TUPLE) PROCEDURE REMOVEBALANCE(ROOT, DIR); REF(NODE) ROOT; INTEGER DIR;
|
|
BEGIN REF(NODE) N; INTEGER BAL;
|
|
N :- ROOT.LINK(OPP(DIR));
|
|
BAL := 2*DIR - 1;
|
|
|
|
IF N.BALANCE = -BAL THEN
|
|
BEGIN ROOT.BALANCE := 0; N.BALANCE := 0;
|
|
REMOVEBALANCE :- NEW TUPLE(SINGLE(ROOT, DIR), FALSE);
|
|
END ELSE
|
|
|
|
IF N.BALANCE = BAL THEN
|
|
BEGIN ADJUSTBALANCE(ROOT, OPP(DIR), -BAL);
|
|
REMOVEBALANCE :- NEW TUPLE(DOUBLE(ROOT, DIR), FALSE);
|
|
END ELSE
|
|
|
|
BEGIN ROOT.BALANCE := -BAL; N.BALANCE := BAL;
|
|
REMOVEBALANCE :- NEW TUPLE(SINGLE(ROOT, DIR), TRUE);
|
|
END
|
|
END REMOVEBALANCE;
|
|
|
|
REF(TUPLE) PROCEDURE REMOVER(ROOT, DATA); REF(NODE) ROOT; REF(KEY) DATA;
|
|
BEGIN INTEGER DIR; BOOLEAN DONE; REF(TUPLE) T;
|
|
|
|
IF ROOT == NONE THEN
|
|
REMOVER :- NEW TUPLE(NONE, FALSE)
|
|
ELSE
|
|
IF ROOT.DATA.EQUAL(DATA) THEN
|
|
BEGIN
|
|
IF ROOT.LINK(0) == NONE THEN
|
|
BEGIN
|
|
REMOVER :- NEW TUPLE(ROOT.LINK(1), FALSE);
|
|
GOTO L;
|
|
END
|
|
|
|
ELSE IF ROOT.LINK(1) == NONE THEN
|
|
BEGIN
|
|
REMOVER :- NEW TUPLE(ROOT.LINK(0), FALSE);
|
|
GOTO L;
|
|
END
|
|
|
|
ELSE
|
|
BEGIN REF(NODE) HEIR;
|
|
HEIR :- ROOT.LINK(0);
|
|
WHILE HEIR.LINK(1) =/= NONE DO
|
|
HEIR :- HEIR.LINK(1);
|
|
ROOT.DATA :- HEIR.DATA;
|
|
DATA :- HEIR.DATA;
|
|
END;
|
|
END;
|
|
DIR := 0;
|
|
IF ROOT.DATA.LESS(DATA) THEN
|
|
DIR := 1;
|
|
T :- REMOVER(ROOT.LINK(DIR), DATA); ROOT.LINK(DIR) :- T.N; DONE := T.B;
|
|
IF DONE THEN
|
|
BEGIN
|
|
REMOVER :- NEW TUPLE(ROOT, TRUE);
|
|
GOTO L;
|
|
END;
|
|
ROOT.BALANCE := ROOT.BALANCE + 1 - 2*DIR;
|
|
IF ROOT.BALANCE = 1 OR ROOT.BALANCE = -1 THEN
|
|
REMOVER :- NEW TUPLE(ROOT, TRUE)
|
|
|
|
ELSE IF ROOT.BALANCE = 0 THEN
|
|
REMOVER :- NEW TUPLE(ROOT, FALSE)
|
|
|
|
ELSE
|
|
REMOVER :- REMOVEBALANCE(ROOT, DIR);
|
|
L:
|
|
END REMOVER;
|
|
|
|
! REMOVE A SINGLE ITEM FROM AN AVL TREE. ;
|
|
! IF KEY DOES NOT EXIST, FUNCTION HAS NO EFFECT. ;
|
|
PROCEDURE REMOVE(TREE, DATA); NAME TREE; REF(NODE) TREE; REF(KEY) DATA;
|
|
BEGIN REF(TUPLE) T;
|
|
T :- REMOVER(TREE, DATA);
|
|
TREE :- T.N;
|
|
END REMOVEM;
|
|
|
|
END.
|