Algorithmen und Datenstrukturen Übung 9: Bayer-Bäume Bayer-Baumknoten Die Klasse CBNode zeigt die Implementierung eines Bayer -Baumknotens 1. Der Konstruktor dieser Klasse leistet die Arbeit und bekommt dazu einen Übergabeparameter (M) geliefert, der die Ordnung des (M-ären) Bayer-Baums beschreibt. import java.util.*; /* * The CBNode class represents on single Node of the Bayer Tree. */ public class CBNode { // Instanzvariable protected Vector key, nodeptr, initkey, initvec; int count; // Konstruktor /* * constructs a single Bayer Tree node with M references to subnodes. */ CBNode(int M) { // System.out.println("CBNode(): constructor invoked!"); nodeptr = new Vector(); initvec = new Vector(); initvec = null; key = new Vector(); initkey = new Vector(); initkey = null; for(int i = 0; i <= M; i++) { nodeptr.addElement((Object)initvec); // System.out.println(i + "ter Nodepointer erzeugt. Wert: " + nodeptr.elementAt(i)); } for(int j = 0; j <= M - 1; j++) { key.addElement((Object)initkey); // System.out.println(j + "ter Key erzeugt. Wert: " + key.elementAt(j)); } count = 0; // System.out.println("count Wert: " + count); } } Bayer-Baum Die Klasse CBayerTree umfaßt den Algorithmus 2 zum Einfügen und Löschen von Bayer-Baum knoten 1 Vgl. pr44200, CBNode.java 2 Vgl. pr44200, CBayerTree.java 1 Algorithmen und Datenstrukturen class CBayerTree { // protected Instanzvariablen /* * Die Variable MAERER definiert die Ordnung des Bayer-Baums, * d.h. der Nachfolgerknoten bzw. Teilbäume eines Knoten * (max. MAERER). Jeder Knoten besteht aus MAERER Referenzen * auf Subknoten und MAERER - 1 Schlüsseln. */ protected int MAERER = 5; /* * contains the reference to the CVisualizeTree class. It will be set in * the constructor. */ protected CVisualizeTree mpCVisualizeTree; /* * contains the reference to the CExtendedCanvas class. It will be set in * the constructor. */ protected CExtendedCanvas mpCExtendedCanvas; /* * Referenz zum Wurzelknoten während der Lebensdauer des Baums. */ protected CBNode root; /* * speichert den neuen Schluessel, der in den baum eingefügt werden soll. */ protected Integer newValue; /* * Indikator fuer den Wurzelknoten. */ private int rootflag = 0; // Public Operationen // Der Konstruktor umfasst zwei Paramerte zur Visualisierung /* public CBayerTree(CExtendedCanvas pCExtendedCanvas, CVisualizeTree pCVisualizeTree); Einfuegen public int Insert(Integer value); ; Rueckgabe: -1, falls Fehlversuch; anderenfalls 0 Parameter: einzufuegender Schluessel Loeschen public int Delete(Integer delValue); ; Rueckgabe: -1, falls Fehlversuch; anderenfalls 0 Parameter: einzufuegender Schluessel public boolean searchkey(int key); Rueckgabe: true, falls der Schlüssel gefunden wurde; anderenfalls false Geschuetzte Methoden protected CBNode insrekurs(CBNode tempnode, Integer insValue); Private Methoden private int delrekurs(CBNode delNode, Integer value); ..... */ } 2 Algorithmen und Datenstrukturen Operationen für Bayer-Bäume Suchen eines Schlüssels Gegeben ist der folgende Ausschnitt eines B-Baums mit N Schlüsseln: +-------------------------------+ | | | Z 0S 1Z 1S 2 .......... Z N-1S NZ N | | | +-------------------------------+ Beim Suchen eines Schlüssels X können folgende Situationen auftreten: 1) S[I] < X < S[I + 1] für 1 <= I <= N Die Suche wird fortgesetzt in dem Knoten, auf den Z[I]^ zeigt. 2) S[N] < X Die Suche wird im Knoten fortgesetzt, auf den Z[N]^ zeigt. 3) X < S[1] Die Suche wird im Knoten fortgesetzt, auf den Z[0]^ zeigt. Hat einer der angegebenen Referenzen den Wert „null“, dann existiert in dem vorliegenden Baum kein Teilbaum, der diesen Schlüssel enthält (d.h. die Suche ist beendet). /* *Rueckgabe ist true, falls der Schlüssel gefunden wurde; * anderenfalls false. */ public boolean searchkey(int key) { boolean found = false; int i = 0, n; CBNode node = root; while(node != null) { i = 0; n = node.count; // search key in actual node while(i < n && key > ((Integer)node.key.elementAt(i)).intValue()) { i++; } // end while if(i < n && key == ((Integer)node.key.elementAt(i)).intValue()) { found = true; } if(node.nodeptr.elementAt(i) != null) { mpCVisualizeTree.MoveLevelDown(i); } node = (CBNode) node.nodeptr.elementAt(i); } // end while (node != null) return found; } // end searchkey Methode Einfügen Bsp.: Der Einfügevorgang in einem Bayer-Baum der Klasse 2 3 Algorithmen und Datenstrukturen 1) Aufnahme der Schlüssel 1, 2, 3, 4 in den Wurzelknoten 1 2 3 4 2) Zusätzlich wird der Schlüssel mit dem Wert 5 eingefügt 1 2 3 4 5 Normalerweise würde jetzt rechts von "4" ein neuer Knotem erzeugt. Das würde aber zu einem Knotenüberlauf führen. Nach dieser Erweiterung enthält der Knoten eine unge rade Zahl von Elementen (2 ⋅ M + 1 ). Dieser große Knoten kann in 2 Söhne zerlegt werden, nur das mittlere Element verbleibt im Vaterknoten. Die neuen Knoten genügen wieder den B-Baum -Eigenschaften und könnem weitere Daten aufnehmen. 3 1 2 4 5 Beschreibung des Algorithmus für das Einfügen Ein neues Element wird grundsätzlich in einen Blattknoten eingefügt. Ist der Knoten mit Schlüsseln voll, so läuft bei der Aufnahme eines weiteren Schlüssels der Knoten über. 2⋅M +---------------------------------------------+ | | | ........... S X-1Z X-1S XZ X ..... | | | +---------------------------------------------+ +----------------------------------------------+ | | | Z0 S1 Z1 .... ZM-1 SM ZM SM+1 ....... Z 2M S2M+1 | | Überlauf | +----------------------------------------------+ Der Knoten wird geteilt: Die vorderen Schlüssel verbleiben im alten Knoten, der Schlüssel mit der Nummer M+1 gelangt als Trennschlüssel in den Vorgängerknoten. Die M Schlüssel mit den Nummern M+2 bis 2 ⋅ M + 1 kommen in den neuen Knoten. +-----------------------------+ | ....S X-1Z X-1S M+1Z YS XZ X .... | +-----------------------------+ +------------------+ |Z 0S 1 .... Z M-1S MZ M| +------------------+ +-----------------------------+ |Z M+1S M+2Z M+2 ..... S2M+1Z 2M+1 | +-----------------------------+ Die geteilten Knoten enthalten genau M Elemente. Das Einfügen eines Elements in der vorangehenden Seite kann diese ebenfalls zum Überlaufen bringen und somit die Aufteilung fortsetzen. Der B-Baum wächst demnach von den Blättern bis zur Wurzel. /* *Einfügen eines neuen Schlüssels. Rückgabe ist –1, falls 4 Algorithmen und Datenstrukturen * es misslingt, anderenfalls 0 * Parameter: value einzufuegender Wert */ public int Insert(Integer value) { if(root == null) { root = new CBNode(MAERER); root.key.setElementAt((Object)value, 0); root.count = 1; } // end if else { if(searchkey(((Integer)value).intValue()) == true) { //System.out.println("double key found and will be ignored!"); return -1; } // end if CBNode result; result = insrekurs(root, value); if(result != null) { CBNode node = new CBNode(MAERER); node.key.setElementAt(newValue, 0); node.nodeptr.setElementAt(root, 0); node.nodeptr.setElementAt(result, 1); node.count = 1; root = node; } // end if(result) } // end else mpCVisualizeTree.DeleteRootKnot(); mpCExtendedCanvas.repaint(); rootflag = 0; this.drawTree(root); mpCExtendedCanvas.repaint(); return 0; } // end Insert() Methode Die Methode „Insert“ ruft „insrekurs() “ auf. Diese rekursive Methode leistet die eigentliche Arbeit /* * der neue Wert wird rekursiv in den Baum eingebracht */ protected CBNode insrekurs(CBNode tempnode, Integer insValue) { CBNode result; result = null; newValue = insValue; if(tempnode.nodeptr.elementAt(0) != null) // kein Blatt -> Rekursion { int pos = 0; while(pos < tempnode.count && newValue.intValue() > ((Integer)tempnode.key.elementAt(pos)).intValue()) { pos++; } // end while result = insrekurs((CBNode)tempnode.nodeptr.elementAt(pos), newValue); if(result == null) { return null; // if result = null: nothing has to be inserted into // node-> finished! } // end if(resul == null) 5 Algorithmen und Datenstrukturen } // end if(tempnode.nodeptr.elementAt(0) != null) // insert a element CBNode node = null; int flag = 0; int s = tempnode.count; if(s >= MAERER - 1) // split the knot { tempnode.count = (MAERER - 1) / 2; node = new CBNode(MAERER); node.count = (MAERER - 1) / 2; for(int d = ((MAERER - 1) / 2); d > 0;) { if(flag != 0 || ((Integer)tempnode.key.elementAt(s - 1)).intValue() > newValue.intValue()) { node.nodeptr.setElementAt(tempnode.nodeptr.elementAt(s), d); node.key.setElementAt(tempnode.key.elementAt(--s), --d); } // end if(flag != 0 ... else { node.nodeptr.setElementAt(result, d); node.key.setElementAt(newValue, --d); flag = 1; } // end else } // end if(s >= MAERER - 1) if(flag != 0 || ((Integer)tempnode.key.elementAt(s - 1)).intValue() > newValue.intValue()) { node.nodeptr.setElementAt(tempnode.nodeptr.elementAt(s), 0); } // end if else { node.nodeptr.setElementAt(result, 0); } // end else } // end if(s >= MAERER - 1) else { tempnode.count++; } // end else // shift for(; s > 0 && ((Integer)tempnode.key.elementAt(s - 1)).intValue() > newValue.intValue(); s--) { tempnode.nodeptr.setElementAt(tempnode.nodeptr.elementAt(s), s + 1); tempnode.key.setElementAt(tempnode.key.elementAt(s - 1), s); } // end for tempnode.key.setElementAt(newValue, s); tempnode.nodeptr.setElementAt(result, s + 1); newValue = (Integer) tempnode.key.elementAt((MAERER - 1) / 2); return node; } // end insrekurs() methode Löschen Grundsätzlich ist zu unterscheiden: 1. Das zu löschende Element ist in einem Blattknoten 2. Das Element ist nicht in einem Blattknoten enthalten. In diesem Fall ist es durch eines der benachbarten Elemente zu ersetzen. Entlang des rechts stehenden Zeigers Z ist hier zum Blattknoten hinabzusteigen und das zu löschende Element durch das äußere linke Element von Z zu ersetzen. 6 Algorithmen und Datenstrukturen Auf jeden Fall darf die Anzahl der Schlüssel im Knoten nicht kleiner als M werden. /* * loescht einen Schlüssel. Rückgabe ist * anderenfalls 0. * * Parameter: zu löschender Wert */ public int Delete(Integer delValue) -1, falls es misslingt; { mpCVisualizeTree.MoveToRoot(); if(searchkey(((Integer)delValue).intValue()) == false) { return -1; } // end if if(delrekurs(root, delValue) == 0) { CBNode temp = root; root = (CBNode)root.nodeptr.elementAt(0); temp = null; } // end if mpCVisualizeTree.DeleteRootKnot(); mpCExtendedCanvas.repaint(); rootflag = 0; this.drawTree(root); mpCExtendedCanvas.repaint(); return 0; } // end Delete() Methode Die eigentliche Arbeit beim Löschen übernimmt die rekursive Methode „delrekurs()“ /* * deletes the value rekursively from the tree. * */ private int delrekurs(CBNode delNode, Integer value) { int result = 0, pos, found = 0; Vector nullVec = new Vector(); nullVec = null; if(delNode != null) { CBNode node; for(pos = 0; pos < delNode.count; pos++) { if(value.intValue() <= ((Integer)delNode.key.elementAt(pos)).intValue()) { if(value.intValue() < ((Integer)delNode.key.elementAt(pos)).intValue()) { result = delrekurs((CBNode)delNode.nodeptr.elementAt(pos), (Integer)value); } // end if else { if(delNode.nodeptr.elementAt(0) == null) // leaf node! { for(; (pos + 1) < delNode.count; pos++) 7 Algorithmen und Datenstrukturen { delNode.key.setElementAt(delNode.key.elementAt(pos + 1), pos); } // end for //System.out.println("Ende weil Blatt!"); return --delNode.count; } // end if else { node = (CBNode)delNode.nodeptr.elementAt(pos + 1); while(node.nodeptr.elementAt(0) != null) { node = (CBNode)node.nodeptr.elementAt(0); } // end while delNode.key.setElementAt(node.key.elementAt(0), pos); //System.out.println("Tausch, loesche rechts"); pos++; result = delrekurs((CBNode)delNode.nodeptr.elementAt(pos), (Integer)delNode.key.elementAt(pos - 1)); } // end else } // end else found = 1; break; } // end if } // end for if(found == 0) { result = delrekurs((CBNode)delNode.nodeptr.elementAt(pos), (Integer)value); } // end if if(result < ((MAERER - 1) / 2)) { CBNode temp; int l = 0, r = 0; if(pos > 0) { l = ((CBNode)delNode.nodeptr.elementAt(pos - 1)).count; } // end if if(pos < delNode.count) { r = ((CBNode)delNode.nodeptr.elementAt(pos + 1)).count; } // end if node = (CBNode)delNode.nodeptr.elementAt(pos); if(l > (MAERER - 1) / 2) // steal a key from left { //System.out.println("klaue einen Schluessel von links"); temp = (CBNode)delNode.nodeptr.elementAt(pos - 1); for(int i = node.count; i > 0; i--) { node.key.setElementAt(node.key.elementAt(i - 1), i); node.nodeptr.setElementAt(node.nodeptr.elementAt(i), i + 1); } // end for node.nodeptr.setElementAt(node.nodeptr.elementAt(0), 1); node.count++; node.key.setElementAt(delNode.key.elementAt(pos - 1), 0); node.nodeptr.setElementAt(temp.nodeptr.elementAt(temp.count), 0); delNode.key.setElementAt(temp.key.elementAt(--temp.count), pos - 1); } // end if else { if(r > (MAERER - 1) / 2) // steal a key from right { // System.out.println("klaue Schluessel von rechts"); temp = (CBNode)delNode.nodeptr.elementAt(pos + 1); 8 Algorithmen und Datenstrukturen node.key.setElementAt(delNode.key.elementAt(pos), node.count); node.count++; node.nodeptr.setElementAt(temp.nodeptr.elementAt(0), node.count); delNode.key.setElementAt(temp.key.elementAt(0), pos); for(int i = 1; i < temp.count; i++) { temp.key.setElementAt(temp.key.elementAt(i), i - 1); temp.nodeptr.setElementAt(temp.nodeptr.elementAt(i), i - 1); } // end for temp.nodeptr.setElementAt(temp.nodeptr.elementAt(temp.count), temp.count - 1); temp.count--; } // end if else { //System.out.println("Knoten verschmelzen !"); if(r == 0) { pos--; } // end if node = (CBNode)delNode.nodeptr.elementAt(pos); temp = (CBNode)delNode.nodeptr.elementAt(pos + 1); node.key.setElementAt(delNode.key.elementAt(pos), node.count++); node.nodeptr.setElementAt(temp.nodeptr.elementAt(0), node.count); for(int i = 0; i < temp.count; i++) { node.key.setElementAt(temp.key.elementAt(i), node.count++); node.nodeptr.setElementAt(temp.nodeptr.elementAt(i + 1), node.count); } // end for // System.out.println( // "Jetzt kann der Knoten rechts daneben entfernt werden!"); delNode.count--; // delNode.nodeptr.elementAt(pos + 1) = null; // geht das so? delNode.nodeptr.setElementAt((Object)nullVec, pos + 1); while(pos < delNode.count) { delNode.key.setElementAt(delNode.key.elementAt(pos + 1), pos); pos++; delNode.nodeptr.setElementAt(delNode.nodeptr.elementAt(pos + 1), pos); } // end while } // end else } // end else } // end if return delNode.count; } // end if else { return 0; } // end else } // end delrekurs() Methode 9 Algorithmen und Datenstrukturen Lösung: CBNode.java // // // // // // // // // // // // // // // ======================================================================= Project to the course OP WS1998/99 Fachhochschule Regensburg Filename: CBNode.java Author : Hr. Thomas Dotzler Version : 2 .1.4.2 Date : 01/06/1999 last modified: 01/20/199 reason: source code documentation Task: This file contains the source code for the implementation of a node balanced tree JAVA. To see what the methods are performing, refer to the project documentation. compile with (JDK-1.1.7): javac CBNode.java // ======================================================================== import java.util.*; /* * The CBNode class represents on single Node of the Bayer Tree. */ public class CBNode { protected Vector key, nodeptr, initkey, initvec; int count; /* * constructs a single Bayer Tree node with M references to subnodes. */ CBNode(int M) { // System.out.println("CBNode(): constructor invoked!"); nodeptr = new Vector(); initvec = new Vector(); initvec = null; key = new Vector(); initkey = new Vector(); initkey = null; for(int i = 0; i <= M; i++) { nodeptr.addElement((Object)initvec); // System.out.println(i + "ter Nodepointer erzeugt. Wert: " + // nodeptr.elementAt(i)); } for(int j = 0; j <= M - 1; j++) { key.addElement((Object)initkey); // System.out.println(j + "ter Key erzeugt. Wert: " + key.elementAt(j)); } count = 0; // System.out.println("count Wert: " + count); } } CBayerTree.java // ======================================================================== 10 Algorithmen und Datenstrukturen // // // // // // // // // // // // // // // // // // Project to the course OP WS1998/99 Fachhochschule Regensburg Filename: CBayerTree.java Author : Hr. Thomas Dotzler, Hr. Thomas Feldbauer, who helped me out with the algorithm in C++ Version : 2.1.4.2 Date : 01/06/1999 last modified: 01/20/199 reason: source code documentation Task: This file contains the source code for the implementation of a balanced tree in JAVA. The essential methods are: public int Insert(Integer value) public int Delete(Integer delValue) compile with (JDK-1.1.7): javac CBayerTree.java ==================================================================== import java.util.*; import java.lang.*; /* * The Class CBayerTree has been designed to represent a balanced * or a so called "Bayer" Tree. * It is implemented to build up trees with different orders where the *order is represented */ class CBayerTree { // protected class parameter /* * The variable <b>MAERER</b> defines the order of the balanced tree. * It also defines how many * subnodes or subtrees each node can have (max. * MAERER). Each node consists of MAERER pointer * to subnodes and MAERER - 1 data fields. */ protected int MAERER = 5; /* * contains the reference to the CVisualizeTree class. It will be set in * the constructor. */ protected CVisualizeTree mpCVisualizeTree; /* * contains the reference to the CExtendedCanvas class. It will be set in * the constructor. */ protected CExtendedCanvas mpCExtendedCanvas; /* * references to the root node as long as the tree existsts. */ protected CBNode root; /* *is used to store the new value that will be inserted into the balanced 11 Algorithmen und Datenstrukturen * tree. */ protected Integer newValue; /* * indicates the root node. */ private int rootflag = 0; // /* * * * */ class constructor Constructs an empty balanced tree. Parameter: pCExtendedCanvas the reference to CExtendedCanvas class. Parameter: pVisualizeTree the reference to CVisualizeTree class. public CBayerTree(CExtendedCanvas pCExtendedCanvas, CVisualizeTree pCVisualizeTree) { root = null; mpCVisualizeTree = pCVisualizeTree; mpCExtendedCanvas = pCExtendedCanvas; ResetTreeWithOrder(MAERER); } // end constructor // public functions /* * inserts a new Value into the tree. Returns -1 if it fails to insert a * value otherwise 0. * * Parameter: value the value to be inserted wrapped by an * <i>Integer</i> object. */ public int Insert(Integer value) { if(root == null) { root = new CBNode(MAERER); root.key.setElementAt((Object)value, 0); root.count = 1; } // end if else { if(searchkey(((Integer)value).intValue()) == true) { //System.out.println("double key found and will be ignored!"); return -1; } // end if CBNode result; result = insrekurs(root, value); if(result != null) { CBNode node = new CBNode(MAERER); node.key.setElementAt(newValue, 0); node.nodeptr.setElementAt(root, 0); node.nodeptr.setElementAt(result, 1); node.count = 1; root = node; } // end if(result) } // end else mpCVisualizeTree.DeleteRootKnot(); 12 Algorithmen und Datenstrukturen mpCExtendedCanvas.repaint(); rootflag = 0; this.drawTree(root); mpCExtendedCanvas.repaint(); return 0; } // end Insert() Methode /* * deletes a value from the tree. Returns -1 if it fails to delete the * value otherwise 0. * * Parameter: delValue the value to be deleted wrapped by an * Integer-Object */ public int Delete(Integer delValue) { mpCVisualizeTree.MoveToRoot(); if(searchkey(((Integer)delValue).intValue()) == false) { return -1; } // end if if(delrekurs(root, delValue) == 0) { CBNode temp = root; root = (CBNode)root.nodeptr.elementAt(0); temp = null; } // end if mpCVisualizeTree.DeleteRootKnot(); mpCExtendedCanvas.repaint(); rootflag = 0; this.drawTree(root); mpCExtendedCanvas.repaint(); return 0; } // end Delete() Methode /* * is used to search a key in the tree. Returns true if the key was found * otherwise false. */ public boolean searchkey(int key) { boolean found = false; int i = 0, n; CBNode node = root; while(node != null) { i = 0; n = node.count; // search key in actual node while(i < n && key > ((Integer)node.key.elementAt(i)).intValue()) { i++; } // end while if(i < n && key == ((Integer)node.key.elementAt(i)).intValue()) { found = true; } if(node.nodeptr.elementAt(i) != null) { mpCVisualizeTree.MoveLevelDown(i); } node = (CBNode) node.nodeptr.elementAt(i); } // end while (node != null) 13 Algorithmen und Datenstrukturen return found; } // end searchkey Methode /* * resets the tree and initializes the tree with the new order * Parameter order the order of the tree */ public void ResetTreeWithOrder(int order) { mpCVisualizeTree.DeleteRootKnot(); mpCVisualizeTree.SetNumberOfPointers(order); mpCExtendedCanvas.repaint(); root = null; MAERER = order; } // end ResetTreeWithOrder() Methode // protected functions /* * inserts the new value rekursively into the tree. */ protected CBNode insrekurs(CBNode tempnode, Integer insValue) { CBNode result; result = null; newValue = insValue; if(tempnode.nodeptr.elementAt(0) != null) // not a leaf -> rekurs { int pos = 0; while(pos < tempnode.count && newValue.intValue() > ((Integer)tempnode.key.elementAt(pos)).intValue()) { pos++; } // end while result = insrekurs((CBNode)tempnode.nodeptr.elementAt(pos), newValue); if(result == null) { return null; // if result = null: nothing has to be inserted into // node-> finished! } // end if(resul == null) } // end if(tempnode.nodeptr.elementAt(0) != null) // insert a element CBNode node = null; int flag = 0; int s = tempnode.count; if(s >= MAERER - 1) // split the knot { tempnode.count = (MAERER - 1) / 2; node = new CBNode(MAERER); node.count = (MAERER - 1) / 2; for(int d = ((MAERER - 1) / 2); d > 0;) { if(flag != 0 || ((Integer)tempnode.key.elementAt(s - 1)).intValue() > newValue.intValue()) { node.nodeptr.setElementAt(tempnode.nodeptr.elementAt(s), d); node.key.setElementAt(tempnode.key.elementAt(--s), --d); } // end if(flag != 0 ... else { node.nodeptr.setElementAt(result, d); node.key.setElementAt(newValue, --d); flag = 1; } // end else } // end if(s >= MAERER - 1) if(flag != 0 || ((Integer)tempnode.key.elementAt(s - 1)).intValue() > 14 Algorithmen und Datenstrukturen newValue.intValue()) { node.nodeptr.setElementAt(tempnode.nodeptr.elementAt(s), 0); } // end if else { node.nodeptr.setElementAt(result, 0); } // end else } // end if(s >= MAERER - 1) else { tempnode.count++; } // end else // shift for(; s > 0 && ((Integer)tempnode.key.elementAt(s - 1)).intValue() > newValue.intValue(); s--) { tempnode.nodeptr.setElementAt(tempnode.nodeptr.elementAt(s), s + 1); tempnode.key.setElementAt(tempnode.key.elementAt(s - 1), s); } // end for tempnode.key.setElementAt(newValue, s); tempnode.nodeptr.setElementAt(result, s + 1); newValue = (Integer) tempnode.key.elementAt((MAERER - 1) / 2); return node; } // end insrekurs() methode /* * deletes the value rekursively from the tree. * */ private int delrekurs(CBNode delNode, Integer value) { int result = 0, pos, found = 0; Vector nullVec = new Vector(); nullVec = null; if(delNode != null) { CBNode node; for(pos = 0; pos < delNode.count; pos++) { if(value.intValue() <= ((Integer)delNode.key.elementAt(pos)).intValue()) { if(value.intValue() < ((Integer)delNode.key.elementAt(pos)).intValue()) { result = delrekurs((CBNode)delNode.nodeptr.elementAt(pos), (Integer)value); } // end if else { if(delNode.nodeptr.elementAt(0) == null) // leaf node! { for(; (pos + 1) < delNode.count; pos++) { delNode.key.setElementAt(delNode.key.elementAt(pos + 1), pos); } // end for //System.out.println("Ende weil Blatt!"); return --delNode.count; } // end if else { node = (CBNode)delNode.nodeptr.elementAt(pos + 1); 15 Algorithmen und Datenstrukturen while(node.nodeptr.elementAt(0) != null) { node = (CBNode)node.nodeptr.elementAt(0); } // end while delNode.key.setElementAt(node.key.elementAt(0), pos); //System.out.println("Tausch, loesche rechts"); pos++; result = delrekurs((CBNode)delNode.nodeptr.elementAt(pos), (Integer)delNode.key.elementAt(pos - 1)); } // end else } // end else found = 1; break; } // end if } // end for if(found == 0) { result = delrekurs((CBNode)delNode.nodeptr.elementAt(pos), (Integer)value); } // end if if(result < ((MAERER - 1) / 2)) { CBNode temp; int l = 0, r = 0; if(pos > 0) { l = ((CBNode)delNode.nodeptr.elementAt(pos - 1)).count; } // end if if(pos < delNode.count) { r = ((CBNode)delNode.nodeptr.elementAt(pos + 1)).count; } // end if node = (CBNode)delNode.nodeptr.elementAt(pos); if(l > (MAERER - 1) / 2) // steal a key from left { //System.out.println("klaue einen Schluessel von links"); temp = (CBNode)delNode.nodeptr.elementAt(pos - 1); for(int i = node.count; i > 0; i--) { node.key.setElementAt(node.key.elementAt(i - 1), i); node.nodeptr.setElementAt(node.nodeptr.elementAt(i), i + 1); } // end for node.nodeptr.setElementAt(node.nodeptr.elementAt(0), 1); node.count++; node.key.setElementAt(delNode.key.elementAt(pos - 1), 0); node.nodeptr.setElementAt(temp.nodeptr.elementAt(temp.count), 0); delNode.key.setElementAt(temp.key.elementAt(--temp.count), pos - 1); } // end if else { if(r > (MAERER - 1) / 2) // steal a key from right { // System.out.println("klaue Schluessel von rechts"); temp = (CBNode)delNode.nodeptr.elementAt(pos + 1); node.key.setElementAt(delNode.key.elementAt(pos), node.count); node.count++; node.nodeptr.setElementAt(temp.nodeptr.elementAt(0), node.count); delNode.key.setElementAt(temp.key.elementAt(0), pos); for(int i = 1; i < temp.count; i++) { temp.key.setElementAt(temp.key.elementAt(i), i - 1); temp.nodeptr.setElementAt(temp.nodeptr.elementAt(i), i - 1); 16 Algorithmen und Datenstrukturen } // end for temp.nodeptr.setElementAt(temp.nodeptr.elementAt(temp.count), temp.count - 1); temp.count--; } // end if else { //System.out.println("Knoten verschmelzen !"); if(r == 0) { pos--; } // end if node = (CBNode)delNode.nodeptr.elementAt(pos); temp = (CBNode)delNode.nodeptr.elementAt(pos + 1); node.key.setElementAt(delNode.key.elementAt(pos), node.count++); node.nodeptr.setElementAt(temp.nodeptr.elementAt(0), node.count); for(int i = 0; i < temp.count; i++) { node.key.setElementAt(temp.key.elementAt(i), node.count++); node.nodeptr.setElementAt(temp.nodeptr.elementAt(i + 1), node.count); } // end for // System.out.println( // "Jetzt kann der Knoten rechts daneben entfernt werden!"); delNode.count--; // delNode.nodeptr.elementAt(pos + 1) = null; // geht das so? delNode.nodeptr.setElementAt((Object)nullVec, pos + 1); while(pos < delNode.count) { delNode.key.setElementAt(delNode.key.elementAt(pos + 1), pos); pos++; delNode.nodeptr.setElementAt(delNode.nodeptr.elementAt(pos + 1), pos); } // end while } // end else } // end else } // end if return delNode.count; } // end if else { return 0; } // end else } // end delrekurs() Methode /* * deletes the visualized Tree */ protected void delTree(CBNode rootNode) { if(rootflag == 0) { for(int k = 0; k < rootNode.count; k++) { mpCVisualizeTree.DeleteKnotValue(k); mpCExtendedCanvas.repaint(); } // end for(int k = 0; k < rootNode.count; k++) rootflag = 1; } // end if(rootflag == 0) if(rootNode != null) { for(int i = 0; i < rootNode.count; i++) { 17 Algorithmen und Datenstrukturen if(rootNode.nodeptr.elementAt(i) != null) { mpCVisualizeTree.MoveLevelDown(i); } // end if delTree((CBNode)rootNode.nodeptr.elementAt(i)); mpCVisualizeTree.DeleteKnotValue(i); mpCExtendedCanvas.repaint(); } // end if if(rootNode.nodeptr.elementAt(rootNode.count) != null) { mpCVisualizeTree.MoveLevelDown(rootNode.count); } // end if delTree((CBNode)rootNode.nodeptr.elementAt(rootNode.count)); mpCVisualizeTree.MoveLevelUp(); for(int k = 0; k < rootNode.count + 1; k++) { mpCVisualizeTree.DeleteSubKnot(k); mpCExtendedCanvas.repaint(); } // end for } // end if(rootNode != null) } // end delTree() Methode /* * draws the tree. */ protected void drawTree(CBNode rootNode) { if(rootNode != null) { if(rootflag == 0) { mpCVisualizeTree.CreateRootKnot(); mpCVisualizeTree.InsertKnotValue(0, ((Integer)rootNode.key.elementAt(0)).intValue()); rootflag = 1; } // end if(rootflag == 0) for(int i = 0; i < rootNode.count; i++) { if(rootNode.nodeptr.elementAt(i) != null) { //System.out.println( // "create SubKnot at pos: " + i + " and move down same pos"); mpCVisualizeTree.InsertNewSubKnot(i); mpCVisualizeTree.MoveLevelDown(i); } // end if drawTree((CBNode)rootNode.nodeptr.elementAt(i)); // System.out.println("insert element: " + rootNode.key.elementAt(i) + // " at pos: " + i); mpCVisualizeTree.InsertKnotValue(i, ((Integer)rootNode.key.elementAt(i)).intValue()); } // end for if(rootNode.nodeptr.elementAt(rootNode.count) != null) { //System.out.println("create SubKnot at pos: " + rootNode.count + // " and move down same pos"); mpCVisualizeTree.InsertNewSubKnot(rootNode.count); mpCVisualizeTree.MoveLevelDown(rootNode.count); } // end if drawTree((CBNode)rootNode.nodeptr.elementAt(rootNode.count)); //System.out.println("move level up"); mpCVisualizeTree.MoveLevelUp(); } // end if(rootNode != null) } // end drawTree() Methode /* 18 Algorithmen und Datenstrukturen * shows the keys in the tree in a in-order run. For test purpose only. */ private void showrekurs(CBNode rootNode) { if(rootNode != null) { for(int i = 0; i < rootNode.count; i++) { showrekurs((CBNode)rootNode.nodeptr.elementAt(i)); System.out.print(rootNode.key.elementAt(i) + " "); } // end for showrekurs((CBNode)rootNode.nodeptr.elementAt(rootNode.count)); } // end if } // end showrekurs() Methode } // End Class CBTree 19