home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
modula2
/
library
/
modula1
/
btree.mod
< prev
next >
Wrap
Text File
|
1987-06-11
|
7KB
|
264 lines
(* Insert and delete elements in a B-tree of page size 2n.
Read a sequence of keys positive values denote insertion,
negative ones deletion. Print the resulting B-tree
after each operation. *)
MODULE btree;
FROM InOut IMPORT WriteInt, WriteLn, WriteString, ReadInt;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
CONST n = 2;
nn = 4; (* page size *)
TYPE ref = POINTER TO page;
item = RECORD
key: INTEGER;
p: ref;
count: INTEGER
END;
page = RECORD
m: [0..nn]; (* # of items *)
p0: ref;
e: ARRAY [1..nn] OF item;
END;
VAR root,q: ref;
x,i: INTEGER;
h: BOOLEAN;
u: item;
PROCEDURE printtree(p: ref; l: INTEGER);
VAR i: INTEGER;
BEGIN
IF p # NIL THEN
WITH p^ DO
FOR i := 1 TO l DO WriteString(' ') END;
FOR i := 1 TO m DO WriteInt(e[i].key,4) END;
WriteLn;
printtree(p0,l+1);
FOR i := 1 TO m DO printtree(e[i].p,l+1) END;
END
END
END printtree;
PROCEDURE search(x: INTEGER; a: ref; VAR h: BOOLEAN; VAR v: item);
(* search key x on B-tree with root a; if found, increment counter. Otherwise
insert an item with key x and count 1 in tree. If an item emerges to be
passed to a lower level, then assign it to v; h := "tree a has become higher" *)
VAR k,l,r: INTEGER;
q: ref;
u: item;
PROCEDURE insert;
VAR i: INTEGER;
b: ref;
BEGIN (* insert u to the right of a^.e[r] *)
WITH a^ DO
IF m < nn THEN
INC(m); h := FALSE;
FOR i := m TO r+2 BY -1 DO e[i] := e[i-1] END;
e[r+1] := u
ELSE (* page a^ is full; split it and assign the emerging item to v *)
NEW(b);
(*FOR i := 1 TO nn DO b^.e[i].p := NIL END;*)
IF r <= n THEN
IF r = n THEN
v := u
ELSE
v := e[n];
FOR i := n TO r+2 BY -1 DO e[i] := e[i-1] END;
e[r+1] := u
END;
FOR i := 1 TO n DO b^.e[i] := a^.e[i+n] END
ELSE (* insert u in right page *)
r := r - n;
v := e[n+1];
FOR i := 1 TO r-1 DO b^.e[i] := a^.e[i+n+1] END;
b^.e[r] := u;
FOR i := r+1 TO n DO b^.e[i] := a^.e[i+n] END
END;
m := n; b^.m := n;
b^.p0 := v.p; v.p := b
END
END
END insert;
BEGIN (* search key x on page a^; h = FALSE *)
IF a = NIL THEN
h := TRUE;
WITH v DO (* item with key x is not in tree *)
key := x;
count := 1;
p := NIL
END
ELSE
WITH a^ DO
l := 1; r := m; (* binary array search *)
REPEAT
k := (l+r) DIV 2;
IF x <= e[k].key THEN r := k-1 END;
IF x >= e[k].key THEN l := k+1 END;
UNTIL r < l;
IF l-r > 1 THEN (* found *)
INC(e[k].count);
h := FALSE
ELSE (* item is not on this page *)
IF r = 0 THEN q := p0 ELSE q := e[r].p END;
search(x,q,h,u);
IF h THEN insert END
END
END
END
END search;
PROCEDURE delete(x: INTEGER; a: ref; VAR h: BOOLEAN);
(* search and delete key x in B-tree a; if a page underlow is necessary,
balance with adjacent page if possible, otherwise merge; h := "page a
is undersize" *)
VAR i,k,l,r: INTEGER;
q: ref;
PROCEDURE underflow(c,a: ref; s: INTEGER; VAR h: BOOLEAN);
(* a = underflow page, c = ancestor page *)
VAR b: ref;
i,k,mb,mc: INTEGER;
BEGIN
mc := c^.m; (* h = TRUE, a^.m := n-1 *)
IF s < mc THEN
INC(s);
b := c^.e[s].p;
mb := b^.m;
k := (mb-n+1) DIV 2; (* k = # of items available on adjacent page b *)
a^.e[n] := c^.e[s];
a^.e[n].p := b^.p0;
IF k > 0 THEN (* move k items from b to a *)
FOR i := 1 TO k-1 DO a^.e[i+n] := b^.e[i] END;
c^.e[s] := b^.e[k];
c^.e[s].p := b;
b^.p0 := b^.e[k].p;
mb := mb - k;
FOR i := 1 TO mb DO b^.e[i] := b^.e[i+k] END;
b^.m := mb;
a^.m := n-1+k;
h := FALSE
ELSE (* merge pages a and b *)
FOR i := 1 TO n DO a^.e[i+n] := b^.e[i] END;
FOR i := s TO mc-1 DO c^.e[i] := c^.e[i+1] END;
a^.m := nn; c^.m := mc-1;
DISPOSE(b)
END
ELSE (* b := page to the left of a *)
IF s = 1 THEN b := c^.p0 ELSE b := c^.e[s-1].p END;
mb := b^.m + 1;
k := (mb-n) DIV 2;
IF k > 0 THEN (* move k items from b to a *)
FOR i := n-1 TO 1 BY -1 DO a^.e[i+k] := a^.e[i] END;
a^.e[k] := c^.e[s];
a^.e[k].p := a^.p0;
mb := mb - k;
FOR i := k-1 TO 1 BY -1 DO a^.e[i] := b^.e[i+mb] END;
a^.p0 := b^.e[mb].p;
c^.e[s] := b^.e[mb];
c^.e[s].p := a;
b^.m := mb - 1;
a^.m := n - 1 + k;
h := FALSE
ELSE
b^.e[mb] := c^.e[s];
b^.e[mb].p := a^.p0;
FOR i := 1 TO n-1 DO b^.e[i+mb] := a^.e[i]; END;
b^.m := nn; c^.m := mc - 1;
DISPOSE(a)
END
END
END underflow;
PROCEDURE del(p: ref; VAR h: BOOLEAN);
VAR q: ref; (* global a.k *)
BEGIN
WITH p^ DO
q := e[m].p;
IF q # NIL THEN
del(q,h);
IF h THEN underflow(p,q,m,h) END
ELSE
p^.e[m].p := a^.e[k].p;
a^.e[k] := p^.e[m];
DEC(m); h := m < n;
END
END
END del;
BEGIN
IF a = NIL THEN
WriteString('key is not in tree ');
WriteLn; h := FALSE
ELSE
WITH a^ DO
l := 1; r := m; (* binary array search *)
REPEAT
k := (l+r) DIV 2;
IF x <= e[k].key THEN r := k-1 END;
IF x >= e[k].key THEN l := k+1 END
UNTIL l > r;
IF r = 0 THEN q := p0 ELSE q := e[r].p END;
IF l-r > 1 THEN
IF q = NIL THEN
DEC(m); h := m < n;
FOR i := k TO m DO e[i] := e[i+1] END;
ELSE
del(q,h);
IF h THEN underflow(a,q,r,h) END
END
ELSE
delete(x,q,h);
IF h THEN underflow(a,q,r,h) END;
END
END
END
END delete;
BEGIN
root := NIL;
LOOP
WriteString('Enter key> ');
ReadInt(x);
IF x = 0 THEN WriteString(' Exiting Enter loop'); WriteLn; EXIT END;
WriteString(' search key '); WriteInt(x,6); WriteLn;
search(x,root,h,u);
IF h THEN
q := root;
NEW(root);
WITH root^ DO
m := 1;
p0 := q;
(*FOR i := 1 TO nn DO e[i].p := NIL END;*)
e[1] := u
END
END;
printtree(root,1);
END;
WriteString(' Key to delete> ');
ReadInt(x);
WHILE x # 0 DO
WriteString(' deleting key '); WriteInt(x,6); WriteLn;
delete(x,root,h);
IF h THEN
IF root^.m = 0 THEN
q := root;
root := q^.p0;
DISPOSE(q)
END
END;
printtree(root,1);
WriteString(' Key to delete> ');
ReadInt(x)
END
END btree.