diff --git a/Aufgabenblatt_9-Aufgabe_1/src/AVLTree.java b/Aufgabenblatt_9-Aufgabe_1/src/AVLTree.java new file mode 100644 index 0000000000000000000000000000000000000000..32ad26025606d28c5dd19f07fc8538a35ba8298b --- /dev/null +++ b/Aufgabenblatt_9-Aufgabe_1/src/AVLTree.java @@ -0,0 +1,254 @@ +public class AVLTree<T extends Comparable<T>> { + + private class Node { // ein Knoten im Baum + T value; // Wert am Knoten + Node left; // Wurzel linker Unterbaum + Node right; // Wurzel rechter Unterbaum + int balance; // hoehe(linker Unterbaum) - hoehe(rechter Unterbaum) + + Node(T val) { + value = val; + left = null; + right = null; + balance = 0; + } + } + + private Node root; // Wurzel des gesamten AVL-Baums + private int size; // Anzahl Knoten im AVL-Baum + + public AVLTree() { + root = null; + size = 0; + } + + public int size() { + return size; + } + + public boolean contains(T elem) { + Node node = root; + int diff; + + while (node != null) { + diff = node.value.compareTo(elem); + if (diff == 0) { + return true; + } + else if (diff>0) { + node = node.left; + } + else { + node = node.right; + } + } + + return false; + } + + public void insert(T elem) { + insert(root,null,elem); + } + + /* + * Rekursives Einfuegen in einen Unterbaum. + * + * node: Der Wurzelknoten des Baumes bzw. Unterbaums, in den eingefuegt wird. + * father: Vaterknoten von node, node ist linker oder rechter Sohn von father + * elem: Der einzufuegende Wert + * + * return: true, falls der Unterbaum durch das Einfuegen hoeher geworden ist, + * sonst false + */ + private boolean insert(Node node, Node father, T elem) { + int diff; + boolean grown; + int balanceDelta; + + if (node==null) { // am leeren Unterbaum angekommen + node=new Node(elem); // dann wird hier ein neuer Knoten erzeugt + if (father==null) { // nur moeglich, wenn der root==null also insgesamt leerer Baum + root = node; // dann besteht der Baum jetzt aus genau einem Knoten + } // ansonsten muessen wir untersuchen, ob der neue Knoten + else if (father.value.compareTo(elem) > 0) { // linker oder rechter Sohn seines Vaters wird. + father.left = node; // Wert im Vater ist groesser, dann wird neuer Knoten + } // linker Sohn + else { // Wert im Vater ist kleiner, dann wird neuer Knoten + father.right = node; // rechter Sohn + } + + size++; // Baum hat insgesamt einen Knoten mehr + return true; // Unterbaum mit node als Wurzel ist gewachsen + } + + // Wenn wir hier angekommen sind, gilt node != null. + // Wir muessen also in einen der beiden Unterbaeume von node einfuegen + + diff = node.value.compareTo(elem); + if (diff == 0) { // Wert elem schon im Baum vorhanden + return false; // kein Einfuegen! + } + else if (diff > 0) { // node.value > elem ==> in linken Unterbaum einfuegen + grown = insert(node.left,node,elem); + balanceDelta = 1; + } + else { // node.value < elem ==> in rechten Unterbaum einfuegen + grown = insert(node.right,node,elem); + balanceDelta = -1; + } + + if (grown) { // wenn der unterbaum von node, in den wir eingefuegt haben, + node.balance += balanceDelta; // gewachsen ist, dann aendert sich der balance-Wert + } // am Knoten node + + if (!grown || node.balance==0) { // Keine Hoehenaenderung oder Fall 2 (Folie 253) + return false; // Baum mit Wurzel node ist insgesamt nicht gewachsen + } + + // Wenn wir hier angekommen sind, ist der Baum mit node als Wurzel gewachsen. + // Es liegt entweder Fall 1 oder Fall 3 vor. + + if (node.balance==1 || node.balance==-1) { // AVL Kriterium noch erfuellt + return true; // Fall 1 (Folie 250) + } // Der Baum ist auf jeden Fall gewachsen + + // Wenn wir hier angekommen sind, ist der Baum mit Wurzel node gewachsen und das + // AVL-Kriterium ist verletzt. + if (node.balance==2) { + if (node.left.balance==1) { + rotateLeftLeft(node); // Fall 3a (Folie 258) + } + else { + rotateLeftRight(node); // LR-Rotation // Fall 3b (Folie 261) + } + } + else { + if (node.right.balance==-1) { + rotateLeftRightSymmetric(node); // Fall symmetrisch zu 3a + } + else { + rotateLeftRightSymmetric(node); // RL-Rotation // Fall symmterisch zu 3b + } + } + + // Ausgleichsrotationen fuehren beim Einfuegen stets dazu, dass der Unterbaum mit + // node als Wurzel nicht gewachsen ist. + + return false; + } + + private void rotateLeftLeft(Node w) { // vgl. Folie 258 + Node v = w.left; + Node a1 = v.left; + Node a2 = v.right; + Node b = w.right; + T tmpval; + Node tmpnode; + + tmpval = w.value; // Werte in den Knoten tauschen + w.value = v.value; + v.value = tmpval; + + tmpnode = w; // Verweise auf Knoten tauschen + w = v; // damit anschliessend wieder gilt: + v = tmpnode; // in Knoten v liegt v.value und in w liegt w.value + + v.left = a1; // Verweise umhaengen + v.right = w; + w.left = a2; + w.right = b; + + v.balance = 0; // Unterbaeume ab v und w sind jetzt auf jeden Fall + w.balance = 0; // vollstaendig ausgeglichen + } + + private void rotateLeftRight(Node w) { + Node v = w.left; + Node u = v.right; + Node a1 = v.left; + Node a2 = u.left; + Node a3 = u.right; + Node b = w.right; + T tmpval; + Node tmpnode; + + tmpval = w.value; // Werte in den Knoten tauschen + w.value = u.value; + u.value = tmpval; + + tmpnode = w; // Verweise auf Knoten tauschen + w = u; // damit anschliessend wieder gilt: + u = tmpnode; // in Knoten v liegt v.value und in w liegt w.value + + u.left = v; + u.right = w; + + v.left = a1; + v.right = a2; + + w.left = a3; + w.right = b; + + u.balance = 0; + v.balance = 0; + w.balance = 0; + } + + private void rotateLeftLeftSymmetric(Node w) { // vgl. Folie 258 + Node v = w.right; + Node a1 = v.right; + Node a2 = v.left; + Node b = w.left; + T tmpval; + Node tmpnode; + + tmpval = w.value; // Werte in den Knoten tauschen + w.value = v.value; + v.value = tmpval; + + tmpnode = w; // Verweise auf Knoten tauschen + w = v; // damit anschliessend wieder gilt: + v = tmpnode; // in Knoten v liegt v.value und in w liegt w.value + + v.right = a1; // Verweise umhaengen + v.left = w; + w.right = a2; + w.left = b; + + v.balance = 0; // Unterbaeume ab v und w sind jetzt auf jeden Fall + w.balance = 0; // vollstaendig ausgeglichen + } + + + private void rotateLeftRightSymmetric(Node w) { + Node v = w.right; + Node u = v.left; + Node a1 = v.right; + Node a2 = u.right; + Node a3 = u.left; + Node b = w.left; + T tmpval; + Node tmpnode; + + tmpval = w.value; // Werte in den Knoten tauschen + w.value = u.value; + u.value = tmpval; + + tmpnode = w; // Verweise auf Knoten tauschen + w = u; // damit anschliessend wieder gilt: + u = tmpnode; // in Knoten v liegt v.value und in w liegt w.value + + u.left = v; + u.right = w; + + v.right = a1; + v.left = a2; + + w.right = a3; + w.left = b; + + u.balance = 0; + v.balance = 0; + w.balance = 0; + } +} diff --git a/Aufgabenblatt_9-Aufgabe_1/src/Aufgabenblatt_9Aufgabe_1.java b/Aufgabenblatt_9-Aufgabe_1/src/Aufgabenblatt_9Aufgabe_1.java new file mode 100644 index 0000000000000000000000000000000000000000..8c36501575ff4e65ada231f61a8a31a908a9a57f --- /dev/null +++ b/Aufgabenblatt_9-Aufgabe_1/src/Aufgabenblatt_9Aufgabe_1.java @@ -0,0 +1,17 @@ +public class Aufgabenblatt_9Aufgabe_1 { + + public static void main(String[] args) { + + AVLTree<Integer> avltree = new AVLTree(); + + avltree.insert(50); + avltree.insert(42); + avltree.insert(23); + avltree.insert(2342); + avltree.insert(55); + avltree.insert(13); + avltree.insert(37); + + System.out.println("Anzahl der Elemente: " + avltree.size()); + } +}