home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume35
/
m2-splay22
/
part01
/
splay.mod
< prev
next >
Wrap
Text File
|
1993-01-20
|
16KB
|
588 lines
IMPLEMENTATION MODULE splay;
(*
Title: Implementation of splay trees
Last Edit: Mon Dec 21 13:20:38 1992
Author: Johan Persson at my16
SCCS: @(#)splay.mod 2.2 92/12/21
Description: This code implements splay tree as described in
Sleator D. and Tarjan R. "Self adjusting
binary trees", JACM Vol 32. No 3, 1985, pp 652-
686.
The implemenation is based on a top down
splaying heuristics as described in section 4 of
the article.
Note: This implementation also supports the operations
'getRankElement' which finds the element in the tree
with a given rank in O(lgn) time) and 'getRank',
(which returns the rank of a given element)
To achive this one must store the weight of a node in
each node (i.e the number of descadents). The
update of this information after each basic
operation takes O(lgn) time.
To maintain this weight it's necessary to use a
stack, since the size of the stack is
specified at compile time this may cause a checked
run time error if the bounds of this stack is
violated.
See 'splay.def' for a complete description
of all procedures.
*)
IMPORT SYSTEM,Storage,splayItem,error;
TYPE
T = POINTER TO head;
Tree = POINTER TO treeNode;
treeNode = RECORD
l,r:Tree; (* left and right links *)
data:splayItem.T; (* stored item *)
weight:CARDINAL; (* number of nodes in subtrees *)
END (* record *);
cmpFunc = PROCEDURE (splayItem.T, splayItem.T) : CARDINAL;
head = RECORD
t : Tree;
nbr : CARDINAL;
END (* record *);
CONST
stackSize = 10000;
VAR
ls : ARRAY [0..stackSize] OF Tree;
rs : ARRAY [0..stackSize] OF Tree;
lp,rp : CARDINAL;
PROCEDURE create(VAR tree:T);
BEGIN (* create *)
Storage.ALLOCATE(tree,SIZE(head));
tree^.t := NIL;
tree^.nbr := 0;
END create;
PROCEDURE destroy(VAR tree:T);
PROCEDURE des(t:Tree);
BEGIN (* des *)
IF t # NIL THEN
des(t^.l);
des(t^.r);
splayItem.destroy(t^.data);
Storage.DEALLOCATE(t,SIZE(treeNode));
END (* if *);
END des;
BEGIN (* destroy *)
des(tree^.t);
Storage.DEALLOCATE(tree,SIZE(head));
tree := NIL;
END destroy;
PROCEDURE nbrElem(tree:T): CARDINAL;
BEGIN
RETURN tree^.nbr;
END nbrElem;
(**)
PROCEDURE insert(tree:T; item:splayItem.T);
VAR n,nn,l,r,node:Tree;
i:CARDINAL;
BEGIN (* insert *)
Storage.ALLOCATE(node,SIZE(treeNode));
node^.data := item;
n := tree^.t;
lp:=0;rp:=0;ls[0]:=NIL;rs[0]:=NIL;
tree^.t := node;
IF n = NIL THEN
node^.l:=NIL; node^.r:=NIL;
ELSE
l:=node; r:=node;
ls[0]:=l; rs[0]:=r;
LOOP
IF l#ls[lp] THEN INC(lp);
IF lp>stackSize THEN error.raise("Internal error splay(insert):\n");HALT;
ELSE ls[lp]:=l; END;
END;
IF r#rs[rp] THEN INC(rp);
IF rp>stackSize THEN error.raise("Internal error splay(insert):\n");HALT;
ELSE rs[rp]:=r; END;
END;
IF splayItem.cmp(item,n^.data) < 0 THEN
nn := n^.l;
IF nn=NIL THEN r^.l := n; l^.r := NIL; EXIT;
ELSIF splayItem.cmp(item,nn^.data) >= 0 THEN
r^.l := n; r := n;
l^.r := nn; l := nn;
n := nn^.r;
IF n=NIL THEN r^.l:=NIL; EXIT; END;
ELSE (* item < data *)
n^.l := nn^.r;
r^.l := nn;
nn^.r := n;
r := nn;
n := nn^.l;
IF n = NIL THEN l^.r := NIL; EXIT; END;
END (* if *);
ELSE (* item >= data *)
nn := n^.r;
IF nn=NIL THEN l^.r := n; r^.l := NIL; EXIT;
ELSIF splayItem.cmp(item,nn^.data) < 0 THEN
l^.r := n; l := n;
r^.l := nn; r:=nn;
n := nn^.l;
IF n=NIL THEN l^.r:=NIL; EXIT; END;
ELSE (* item >= data *)
n^.r := nn^.l;
l^.r := nn;
nn^.l := n;
l := nn;
n := nn^.r;
IF n=NIL THEN r^.l := NIL; EXIT; END;
END (* if *)
END (* if *);
END (* loop *);
IF l#ls[lp] THEN INC(lp); ls[lp]:=l; END;
IF r#rs[rp] THEN INC(rp); rs[rp]:=r; END;
(*
** Now, walk back up the left AND right built tree, i.e all nodes
** that are smaller (and bigger) than the node searched for,
** and update all weights. This is done using an explicit stack ls
** and lr.
*)
FOR i := lp TO 0 BY -1 DO
n:=ls[i]; n^.weight:=1;
nn:=n^.l;
IF nn#NIL THEN
nn^.weight:=1;
IF nn^.l#NIL THEN nn^.weight:=nn^.weight+nn^.l^.weight; END;
IF nn^.r#NIL THEN nn^.weight:=nn^.weight+nn^.r^.weight; END;
n^.weight:=n^.weight+nn^.weight;
END;
nn:=n^.r;
IF nn#NIL THEN n^.weight:=n^.weight+nn^.weight; END;
END (* for *);
FOR i := rp TO 0 BY -1 DO
n:=rs[i]; n^.weight:=1;
nn:=n^.r;
IF nn#NIL THEN
nn^.weight:=1;
IF nn^.l#NIL THEN nn^.weight:=nn^.weight+nn^.l^.weight; END;
IF nn^.r#NIL THEN nn^.weight:=nn^.weight+nn^.r^.weight; END;
n^.weight:=n^.weight+nn^.weight;
END;
nn:=n^.l;
IF nn#NIL THEN n^.weight:=n^.weight+nn^.weight; END;
END (* for *);
nn := node^.r;
node^.r := node^.l;
node^.l := nn;
END (* if empty tree*);
INC(tree^.nbr);
END insert;
(* *)
PROCEDURE delete(tree:T; item:splayItem.T);
VAR l,r,nnn,nn,n,pnn:Tree;
left,right:treeNode;
fFound:BOOLEAN;
i:CARDINAL;
PROCEDURE replace(VAR p:Tree; n:Tree);
VAR r,pr:Tree;
BEGIN (* replace *)
r:=n^.l;
IF r=NIL THEN p:=n^.r;
ELSE
IF r^.r=NIL THEN p:=r; p^.r:=n^.r;
ELSE
WHILE r^.r#NIL DO DEC(r^.weight); pr:=r; r:=r^.r; END;
pr^.r:=r^.l;
r^.l:=n^.l; r^.r:=n^.r;
p:=r;
END;
END (* if *);
splayItem.destroy(n^.data);
Storage.DEALLOCATE(n,SIZE(treeNode));
DEC(tree^.nbr);
END replace;
PROCEDURE fixWeight(n:Tree);
VAR nn:Tree;
BEGIN (* fixWeight *)
n^.weight:=1;
nn:=n^.r;
IF nn#NIL THEN
nn^.weight:=1;
IF nn^.l#NIL THEN INC(nn^.weight,nn^.l^.weight); END;
IF nn^.r#NIL THEN INC(nn^.weight,nn^.r^.weight); END;
INC(n^.weight,nn^.weight);
END;
nn:=n^.l;
IF nn#NIL THEN
nn^.weight:=1;
IF nn^.l#NIL THEN INC(nn^.weight,nn^.l^.weight); END;
IF nn^.r#NIL THEN INC(nn^.weight,nn^.r^.weight); END;
INC(n^.weight,nn^.weight);
END;
END fixWeight;
BEGIN (* delete *)
l:=SYSTEM.ADR(left); r:=SYSTEM.ADR(right);
l^.l:=NIL; l^.r:=NIL;
r^.l:=NIL; r^.r:=NIL;
lp:=0;rp:=0;ls[0]:=l;rs[0]:=r;
n := tree^.t;
IF n=NIL THEN RETURN;
ELSIF splayItem.cmp(n^.data,item)=0 THEN replace(tree^.t,n);
ELSE
LOOP
IF l#ls[lp] THEN INC(lp);
IF lp>stackSize THEN error.raise("Internal error splay(delete):\n");HALT;
ELSE ls[lp]:=l; END;
END;
IF r#rs[rp] THEN INC(rp);
IF rp>stackSize THEN error.raise("Internal error/delete):\n");HALT;
ELSE rs[rp]:=r; END;
END;
IF splayItem.cmp(item,n^.data)<0 THEN
nn:=n^.l;
IF nn=NIL THEN EXIT;
ELSE
IF splayItem.cmp(item,nn^.data)=0 THEN
replace(n^.l,nn);
EXIT;
ELSIF splayItem.cmp(item,nn^.data)<0 THEN
nnn:=nn^.l;
IF nnn#NIL THEN
IF splayItem.cmp(item,nnn^.data)=0 THEN
replace(nn^.l,nnn);
r^.l:=n; r:=n; n:=nn;
EXIT;
ELSE (* case III *)
n^.l:=nn^.r;
r^.l:=nn; r:=nn;
nn^.r:=n;
n:=nnn;
END (* if *);
ELSE (* nnn=NIL *)
r^.l:=n; r:=n; n:=nn;
EXIT;
END (* if nnn#NIL *);
ELSE (* item > n^.data *)
nnn:=nn^.r;
IF nnn#NIL THEN
IF splayItem.cmp(item,nnn^.data)=0 THEN
replace(nn^.r,nnn);
r^.l:=n; r:=n; n:=nn;
EXIT;
ELSE (* case V *)
l^.r:=nn; l:=nn;
r^.l:=n; r:=n;
n:=nnn;
END (* if *);
ELSE (* nnn=NIL *)
r^.l:=n; r:=n; n:=nn;
EXIT;
END (* if nnn#NIL *);
END (* if *);
END (* if nn#NIL *);
ELSE (* item>n^.data *)
nn:=n^.r;
IF nn=NIL THEN EXIT;
ELSE
IF splayItem.cmp(item,nn^.data)=0 THEN
replace(n^.r,nn);
EXIT;
ELSIF splayItem.cmp(item,nn^.data)>0 THEN
nnn:=nn^.r;
IF nnn#NIL THEN
IF splayItem.cmp(item,nnn^.data)=0 THEN
replace(nn^.r,nnn);
l^.r:=n; l:=n; n:=nn;
EXIT;
ELSE (* case IV *)
n^.r:=nn^.l;
l^.r:=nn; l:=nn;
nn^.l:=n;
n:=nnn;
END (* if *);
ELSE (* nnn=NIL *)
l^.r:=n; l:=n; n:=nn;
EXIT;
END (* if nnn#NIL *);
ELSE (* item < n^.data *)
nnn:=nn^.l;
IF nnn#NIL THEN
IF splayItem.cmp(item,nnn^.data)=0 THEN
replace(nn^.l,nnn);
l^.r:=n; l:=n; n:=nn;
EXIT;
ELSE (* case VI *)
l^.r:=n; l:=n;
r^.l:=nn; r:=nn;
n:=nnn;
END (* if *);
ELSE (* nnn=NIL *)
l^.r:=n; l:=n; n:=nn;
EXIT;
END (* if nnn#NIL *);
END (* if *);
END (* if nn#nil *);
END (* if *);
END (* loop *);
IF l#ls[lp] THEN INC(lp); ls[lp]:=l; END;
IF r#rs[rp] THEN INC(rp); rs[rp]:=r; END;
l^.r:=n^.l; r^.l:=n^.r;
n^.l:=left.r; n^.r:=right.l;
tree^.t:=n;
(*
** Now, walk back up the left AND right built tree, i.e all nodes
** that are smaller (and bigger) than the node searched for,
** and update all weights. This is done using an explicit stack ls
** and lr.
*)
FOR i := lp TO 1 BY -1 DO
fixWeight(ls[i]);
END (* for *);
FOR i := rp TO 1 BY -1 DO
fixWeight(rs[i]);
END (* for *);
END;
IF tree^.t#NIL THEN fixWeight(tree^.t); END;
END delete;
(* *)
PROCEDURE find(tree:T; item:splayItem.T;VAR found:splayItem.T): BOOLEAN;
VAR l,r,nnn,nn,n:Tree;
left,right:treeNode;
fFound : BOOLEAN;
i:CARDINAL;
BEGIN (* find *)
l:=SYSTEM.ADR(left); r:=SYSTEM.ADR(right);
l^.l:=NIL; l^.r:=NIL;
r^.l:=NIL; r^.r:=NIL;
fFound:=FALSE;
n := tree^.t;
lp:=0;rp:=0;ls[0]:=l;rs[0]:=r;
IF n=NIL THEN RETURN FALSE;
ELSIF splayItem.cmp(n^.data,item)=0 THEN
found:=n^.data;
RETURN TRUE;
ELSE
LOOP
IF l#ls[lp] THEN INC(lp);
IF lp>stackSize THEN error.raise("Internal error splay(find):\n");HALT;
ELSE ls[lp]:=l; END;
END;
IF r#rs[rp] THEN INC(rp);
IF rp>stackSize THEN error.raise("Internal error splay(find):\n");HALT;
ELSE rs[rp]:=r; END;
END;
IF splayItem.cmp(item,n^.data)=0 THEN
found:=n^.data; fFound:=TRUE;
EXIT;
ELSIF splayItem.cmp(item,n^.data)<0 THEN
nn:=n^.l;
IF nn=NIL THEN EXIT;
ELSE
IF splayItem.cmp(item,nn^.data)=0 THEN (* case I *)
r^.l:=n; r:=n; n:=nn;
found:=n^.data; fFound:=TRUE;
EXIT;
ELSIF splayItem.cmp(item,nn^.data)<0 THEN
nnn:=nn^.l;
IF nnn#NIL THEN (* case III *)
n^.l:=nn^.r;
r^.l:=nn; r:=nn;
nn^.r:=n; n:=nnn;
ELSE (* nnn=NIL *)
r^.l:=n; r:=n; n:=nn;
EXIT;
END (* if nnn#NIL *);
ELSE (* item > nn^.data *)
nnn:=nn^.r;
IF nnn#NIL THEN (* case V *)
l^.r:=nn; l:=nn;
r^.l:=n; r:=n; n:=nnn;
ELSE (* nnn=NIL *)
r^.l:=n; r:=n; n:=nn;
EXIT;
END (* if nnn#NIL *);
END (* if *);
END (* if nn#NIL *);
ELSE (* item>n^.data *)
nn:=n^.r;
IF nn=NIL THEN EXIT;
ELSE
IF splayItem.cmp(item,nn^.data)=0 THEN (* case II *)
l^.r:=n; l:=n; n:=nn;
found:=n^.data; fFound:=TRUE;
EXIT;
ELSIF splayItem.cmp(item,nn^.data)>0 THEN
nnn:=nn^.r;
IF nnn#NIL THEN (* case IV *)
n^.r:=nn^.l;
l^.r:=nn; l:=nn;
nn^.l:=n; n:=nnn;
ELSE (* nnn=NIL *)
l^.r:=n; l:=n; n:=nn;
EXIT;
END (* if nnn#NIL *);
ELSE (* item < nn^.data *)
nnn:=nn^.l;
IF nnn#NIL THEN (* case VI *)
l^.r:=n; l:=n;
r^.l:=nn; r:=nn; n:=nnn;
ELSE (* nnn=NIL *)
l^.r:=n; l:=n; n:=nn;
EXIT;
END (* if nnn#NIL *);
END (* if cmp(...) *);
END (* if nn=nil *);
END (* if cmp(...) *);
END (* loop *);
IF l#ls[lp] THEN INC(lp); ls[lp]:=l; END;
IF r#rs[rp] THEN INC(rp); rs[rp]:=r; END;
r^.l:=n^.r; l^.r:=n^.l;
n^.l:=left.r; n^.r:=right.l;
tree^.t:=n;
(*
** Now, walk back up the left AND right built tree, i.e all nodes
** that are smaller (and bigger) than the node searched for,
** and update all weights. This is done using an explicit stack ls
** and lr.
*)
FOR i := lp TO 0 BY -1 DO
n:=ls[i]; n^.weight:=1;
nn:=n^.l;
IF nn#NIL THEN
nn^.weight:=1;
IF nn^.l#NIL THEN nn^.weight:=nn^.weight+nn^.l^.weight; END;
IF nn^.r#NIL THEN nn^.weight:=nn^.weight+nn^.r^.weight; END;
n^.weight:=n^.weight+nn^.weight;
END;
nn:=n^.r;
IF nn#NIL THEN n^.weight:=n^.weight+nn^.weight; END;
END (* for *);
FOR i := rp TO 0 BY -1 DO
n:=rs[i]; n^.weight:=1;
nn:=n^.r;
IF nn#NIL THEN
nn^.weight:=1;
IF nn^.l#NIL THEN nn^.weight:=nn^.weight+nn^.l^.weight; END;
IF nn^.r#NIL THEN nn^.weight:=nn^.weight+nn^.r^.weight; END;
n^.weight:=n^.weight+nn^.weight;
END;
nn:=n^.l;
IF nn#NIL THEN n^.weight:=n^.weight+nn^.weight; END;
END (* for *);
END;
RETURN fFound;
END find;
PROCEDURE getRank(tree:T; item:splayItem.T): CARDINAL;
VAR t,p:Tree;rank:CARDINAL;
BEGIN (* getRank *)
t:=tree^.t;
p:=NIL;
rank:=1;
LOOP
IF t = NIL THEN
RETURN 0;
ELSE
IF splayItem.cmp(t^.data,item)=0 THEN
IF t^.l # NIL THEN
RETURN rank+t^.l^.weight;
ELSE
RETURN rank;
END;
ELSIF splayItem.cmp(t^.data,item) > 0 THEN
p:=t;
t := t^.l;
ELSE
IF t^.l#NIL THEN
rank:=rank+t^.l^.weight+1;
ELSE
INC(rank);
END;
p:=t;
t := t^.r
END;
END (* if *);
END (* loop *);
END getRank;
PROCEDURE getRankElement(tree:T; r:CARDINAL; VAR found:splayItem.T):BOOLEAN;
VAR n:Tree;rank,weight:CARDINAL;
BEGIN (* getRankElement *)
n:=tree^.t;
rank:=0;
WHILE n#NIL DO
IF n^.l#NIL THEN weight:=n^.l^.weight+1;
ELSE weight:=1; END;
IF r=rank+weight THEN
found:=n^.data;
RETURN TRUE;
ELSIF r<rank+weight THEN
n:=n^.l;
ELSE
rank:=rank+weight;
n:=n^.r;
END (* if *);
END;
RETURN FALSE;
END getRankElement;
PROCEDURE mapIn(tree:T; f:auxFunc);
PROCEDURE mI(t:Tree);
BEGIN (* mI *)
IF t # NIL THEN mI(t^.l); f(t^.data); mI(t^.r); END;
END mI;
BEGIN (* mapIn *)
mI(tree^.t);
END mapIn;
PROCEDURE mapPre(tree:T; f:auxFunc);
PROCEDURE mPr(t:Tree);
BEGIN (* mPr *)
IF t # NIL THEN f(t^.data); mPr(t^.l); mPr(t^.r); END;
END mPr;
BEGIN (* mapPre *)
mPr(tree^.t);
END mapPre;
PROCEDURE mapPos(tree:T; f:auxFunc);
PROCEDURE mPo(t:Tree);
BEGIN (* mPo *)
IF t # NIL THEN mPo(t^.l); mPo(t^.r); f(t^.data); END;
END mPo;
BEGIN (* mapPos *)
mPo(tree^.t);
END mapPos;
END splay.