home *** CD-ROM | disk | FTP | other *** search
- (*-------------------------------------------------------------------------*)
- (* *)
- (* Amiga Oberon Library Module: AVLTrees Date: 02-Nov-92 *)
- (* *)
- (* © 1992 by Fridtjof Siebert *)
- (* *)
- (*-------------------------------------------------------------------------*)
-
- MODULE AVLTrees;
-
- IMPORT BT * := BasicTypes,
- BI * := BinaryTrees;
-
- TYPE
-
- Node * = POINTER TO NodeDesc;
- NodeDesc * = RECORD (BI.NodeDesc)
- bal : INTEGER;
- END;
-
-
- Root * = POINTER TO RootDesc;
- RootDesc * = RECORD (BI.RootDesc) END;
-
-
- CONST
-
- (* Node.bal *)
- left = -1;
- ok = 0;
- right = 1;
-
-
- TYPE
- String * = ARRAY 80 OF CHAR;
-
- SNode * = POINTER TO SNodeDesc;
- SNodeDesc * = RECORD (NodeDesc)
- name * : String;
- END;
-
- SRoot * = POINTER TO SRootDesc;
- SRootDesc * = RECORD (RootDesc)
- findstr: String;
- END;
-
-
- (*-------------------------------------------------------------------------*)
-
-
- (*------ Create: ------*)
-
-
- PROCEDURE Create*(): Root;
- (*
- * alloziert neuen, leeren AVL-Baum
- *)
-
- VAR
- r: Root;
-
- BEGIN
- NEW(r); RETURN r;
- END Create;
-
-
- (*------ Add: ------*)
-
-
- PROCEDURE (root: Root) Add* (node: BT.ANY);
-
- (* fügt node in den Baum ein.
- * War ein gleichnamiger Knoten bereits im Baum, wird der Baum nicht
- * verändert und root.addOk auf FALSE gesetzt.
- *
- * require
- * node IS Node
- *
- *)
-
- VAR
- res: BOOLEAN;
- grown: BOOLEAN;
- n1,n2: Node;
-
- PROCEDURE Search(VAR n: Node);
-
- VAR c: LONGINT;
-
- BEGIN
- IF n=NIL THEN (* neues Element einfügen: *)
- grown := TRUE;
- n := node(Node);
- n.l := NIL; n.r := NIL; n.bal := 0;
- res := TRUE;
- ELSE
- c := n.Compare(node(Node));
- IF c>0 THEN
- Search(n.l(Node));
- IF grown THEN (* linker Zweig gewachsen: *)
- CASE n.bal OF
- right: n.bal := ok; grown := FALSE |
- ok: n.bal := left |
- left: n1 := n.l(Node); (* rebalance *)
- IF n1.bal = left THEN (* einfache LL Rotation *)
- n.l := n1.r; n1.r := n; n.bal := ok; n := n1
- ELSE (* doppelte LR Rotation *)
- n2 := n1.r(Node); n1.r := n2.l; n2.l := n1; n.l := n2.r; n2.r := n;
- IF n2.bal=left THEN n .bal := right ELSE n .bal := ok END;
- IF n2.bal=right THEN n1.bal := left ELSE n1.bal := ok END;
- n := n2;
- END;
- n.bal := ok; grown := FALSE |
- END;
- END;
- ELSIF c<0 THEN
- Search(n.r(Node));
- IF grown THEN (* rechter Zweig gewachsen: *)
- CASE n.bal OF
- left: n.bal := ok; grown := FALSE |
- ok: n.bal := right |
- right: n1 := n.r(Node); (* rebalance *)
- IF n1.bal = right THEN (* einfache RR Rotation *)
- n.r := n1.l; n1.l := n; n.bal := ok; n := n1
- ELSE (* doppelte RL Rotation *)
- n2 := n1.l(Node); n1.l := n2.r; n2.r := n1;
- n.r := n2.l; n2.l := n;
- IF n2.bal = right THEN n .bal := left ELSE n .bal := ok END;
- IF n2.bal = left THEN n1.bal := right ELSE n1.bal := ok END;
- n := n2;
- END;
- n.bal := ok; grown := FALSE |
- END;
- END;
- ELSE
- grown := FALSE;
- res := FALSE;
- END;
- END;
- END Search;
-
- BEGIN
- Search(root.root(Node));
- root.addOk := res;
- END Add;
-
-
- (*------ Remove: ------*)
-
-
- PROCEDURE (root: Root) Remove* (node: BT.ANY);
-
- (* Entfernt node aus dem Baum.
- * War node nicht im Baum, wird der Baum nicht verändert und roo.remOk auf FALSE
- * gesetzt.
- *
- * require
- * node IS Node
- *)
-
- VAR
- h: BOOLEAN;
- deleted: BOOLEAN;
-
-
- PROCEDURE BalL(VAR n: Node);
- VAR n1, n2 : Node;
- b1, b2 : INTEGER;
- BEGIN
- CASE n.bal OF
- left: n.bal := ok |
- ok: n.bal := right; h := FALSE |
- right: n1 := n.r(Node); b1 := n1.bal; (* rebalance *)
- IF b1 # left THEN (* single RR rotation *)
- n.r := n1.l; n1.l := n;
- IF b1 = ok THEN n.bal := right; n1.bal := left; h := FALSE
- ELSE n.bal := ok; n1.bal := ok; END;
- n := n1;
- ELSE (* double RL rotation *)
- n2 := n1.l(Node); b2 := n2.bal;
- n1.l := n2.r; n2.r := n1;
- n .r := n2.l; n2.l := n;
- IF b2 = right THEN n .bal := left ELSE n .bal := ok END;
- IF b2 = left THEN n1.bal := right ELSE n1.bal := ok END;
- n := n2; n2.bal := ok;
- END |
- END;
- END BalL;
-
- PROCEDURE BalR(VAR n: Node);
- VAR n1, n2 : Node;
- b1, b2 : INTEGER;
- BEGIN
- CASE n.bal OF
- right: n.bal := ok |
- ok: n.bal := left; h := FALSE |
- left: n1 := n.l(Node); b1 := n1.bal; (* rebalance *)
- IF b1 # right THEN (* single LL rotation *)
- n.l := n1.r; n1.r := n;
- IF b1 = ok THEN n.bal := left; n1.bal := right; h := FALSE
- ELSE n.bal := ok; n1.bal := ok; END;
- n := n1;
- ELSE (* double LR rotation *)
- n2 := n1.r(Node); b2 := n2.bal;
- n1.r := n2.l; n2.l := n1;
- n .l := n2.r; n2.r := n;
- IF b2 = left THEN n .bal := right ELSE n .bal := ok END;
- IF b2 = right THEN n1.bal := left ELSE n1.bal := ok END;
- n := n2; n2.bal := ok;
- END |
- END;
- END BalR;
-
- PROCEDURE Rem(VAR n: Node);
-
- VAR
- c: LONGINT;
- New,Q: Node;
-
- PROCEDURE del(VAR m: Node);
- BEGIN
- IF m.r#NIL THEN
- del(m.r(Node)); IF h THEN BalR(m) END
- ELSE
- New := m;
- m := m.l(Node);
- h := TRUE;
- END;
- END del;
-
- BEGIN
- IF n # NIL THEN
- c := n.Compare(node(Node));
- IF c>0 THEN Rem(n.l(Node)); IF h THEN BalL(n) END
- ELSIF c<0 THEN Rem(n.r(Node)); IF h THEN BalR(n) END
- ELSE
- deleted := TRUE;
- IF n.r=NIL THEN n := n.l(Node); h := TRUE
- ELSIF n.l=NIL THEN n := n.r(Node); h := TRUE
- ELSE
- Q := n;
- del(n.l(Node));
- n := New;
- n.l := Q.l;
- n.r := Q.r;
- n.bal := Q.bal;
- IF h THEN BalL(n) END
- END;
- END;
- END;
- END Rem;
-
- BEGIN
- h := FALSE; deleted := FALSE; Rem(root.root(Node)); root.remOk := deleted;
- END Remove;
-
-
- (*-------------------------------------------------------------------------*)
-
-
- PROCEDURE (a: SNode) Compare*(b: BT.COMPAREABLE): LONGINT;
-
- BEGIN
- WITH b: SNode DO
- IF a.name>b.name THEN RETURN 1
- ELSIF a.name<b.name THEN RETURN -1
- ELSE RETURN 0 END;
- END;
- END Compare;
-
-
- PROCEDURE (a: SNode) Find*(root: BI.Root): LONGINT;
-
- BEGIN
- WITH root: SRoot DO
- IF a.name>root.findstr THEN RETURN 1
- ELSIF a.name<root.findstr THEN RETURN -1
- ELSE RETURN 0 END;
- END;
- END Find;
-
-
- (*-------------------------------------------------------------------------*)
-
-
- (*------ SCreate: ------*)
-
-
- PROCEDURE SCreate*(): SRoot;
- (*
- * alloziert neuen, leeren String-AVL-Baum
- *)
-
- VAR
- r: SRoot;
-
- BEGIN
- NEW(r); RETURN r;
- END SCreate;
-
-
- (*------ SFind: ------*)
-
-
- PROCEDURE (root: SRoot) SFind*(str: String): SNode;
-
- (* Sucht den Knoten mit dem Namen str und gibt seine Adresse oder NIL
- bei Mißerfolg zurück. *)
-
- VAR n: BI.Node;
-
- BEGIN
- root.findstr := str;
- n := root.Find();
- RETURN n(SNode);
- END SFind;
-
-
- (*-------------------------------------------------------------------------
-
- Bei String-AVL-Bäumen können die Prozeduren Remove, DoForward, DoBackward
- und Dispose von oben verwendent werden. Sie sind deshalb nicht noch
- einmal Implementiert.
-
- -------------------------------------------------------------------------*)
-
- END AVLTrees.
-
-
-
-
-
-
-