package trees; import java.util.LinkedList; import java.util.List; import java.util.Queue; class AVL { int value; AVL left, right; int height; private AVL(int value) { this.left = this.right = null; this.value = value; this.height = 1; } private AVL(AVL left, int value, AVL right) { this.left = left; this.value = value; this.right = right; this.height = 1 + Math.max(height(left), height(right)); } static int height(AVL a) { return (a == null) ? 0 : a.height; } static boolean contains(AVL a, int x) { while (a != null) { if (x == a.value) return true; a = (x < a.value) ? a.left : a.right; } return false; } static AVL add(AVL b, int x) { if (b == null) return new AVL(x); if (x < b.value) b.left = add(b.left, x); else if (x > b.value) b.right = add(b.right, x); return balance(b); } // suppose b != null static int getMin(AVL b) { while (b.left != null) b = b.left; return b.value; } // suppose b != null static AVL removeMin(AVL b) { if (b.left == null) return b.right; b.left = removeMin(b.left); return balance(b); } static AVL remove(AVL b, int x) { if (b == null) return null; if (x < b.value) b.left = remove(b.left, x); else if (x > b.value) b.right = remove(b.right, x); else { // x == b.value if (b.right == null) return b.left; if (b.left == null) // optim return b.right; b.value = getMin(b.right); b.right = removeMin(b.right); } return balance(b); } static LinkedList<Integer> toList(AVL t) { LinkedList<Integer> l = new LinkedList<Integer>(); toList(l, t); return l; } private static void toList(LinkedList<Integer> l, AVL t) { if (t == null) return; toList(l, t.left); l.add(t.value); toList(l, t.right); } static int size(AVL t) { if (t == null) return 0; return 1 + size(t.left) + size(t.right); } /* équilibrage * * tout se passe ici : le code ci-dessus est le même que dans BSTSet * si on omet les occurrences de balance */ // rotation droite (simple) private static AVL rotateRight(AVL t) { assert t != null && t.left != null; AVL l = t.left; t.left = l.right; l.right = t; t.height = 1 + Math.max(height(t.left), height(t.right)); l.height = 1 + Math.max(height(l.left), height(l.right)); return l; } // rotation gauche (simple) private static AVL rotateLeft(AVL t) { assert t != null && t.right != null; AVL r = t.right; t.right = r.left; r.left = t; t.height = 1 + Math.max(height(t.left), height(t.right)); r.height = 1 + Math.max(height(r.left), height(r.right)); return r; } private static AVL balance(AVL t) { assert t != null; AVL l = t.left, r = t.right; int hl = height(l), hr = height(r); if (hl > hr + 1) { AVL ll = l.left, lr = l.right; if (height(ll) >= height(lr)) return rotateRight(t); else { t.left = rotateLeft(t.left); return rotateRight(t); } } else if (hr > hl + 1) { AVL rl = r.left, rr = r.right; if (height(rr) >= height(rl)) return rotateLeft(t); else { t.right = rotateRight(t.right); return rotateLeft(t); } } else { t.height = 1 + Math.max(hl, hr); return t; } } // file -> AVL en temps linéaire static AVL ofList(Queue<Integer> l, int n) { if (n == 0) return null; int n1 = (n - 1) / 2; AVL left = ofList(l, n1); int v = l.poll(); AVL right = ofList(l, n - n1 - 1); return new AVL(left, v, right); } static AVL ofList(Queue<Integer> l) { return ofList(l, l.size()); } // on en déduit des opérations ensemblistes static AVL union(AVL t1, AVL t2) { return ofList(listUnion(toList(t1), toList(t2))); } private static LinkedList<Integer> listUnion(LinkedList<Integer> l1, LinkedList<Integer> l2) { LinkedList<Integer> l = new LinkedList<Integer>(); while (!l1.isEmpty() || !l2.isEmpty()) { if (l2.isEmpty() || !l1.isEmpty() && l1.peek() <= l2.peek()) l.add(l1.remove()); else l.add(l2.remove()); } return l; } private static void stringOfTree(StringBuffer sb, AVL t) { if (t == null) return; sb.append("("); stringOfTree(sb, t.left); sb.append("" + t.value + "[" + t.height + "]"); stringOfTree(sb, t.right); sb.append(")"); } public static String stringOfTree(AVL t) { StringBuffer sb = new StringBuffer(); stringOfTree(sb, t); return sb.toString(); } public String toString() { return stringOfTree(this); } // quelques fonctions pour vérifier qu'il s'agit bien d'un AVL static boolean isAVL(AVL t) { return isBST(t) && isBalanced(t); } private static boolean isBST(AVL t) { return isBST(t, Integer.MIN_VALUE, Integer.MAX_VALUE); } private static boolean isBST(AVL t, int min, int max) { if (t == null) return true; if (t.value <= min) return false; if (t.value >= max) return false; return isBST(t.left, min, t.value) && isBST(t.right, t.value, max); } private static boolean isBalanced(AVL t) { if (t == null) return true; if (Math.abs(height(t.left) - height(t.right)) > 1) return false; return isBalanced(t.left) && isBalanced(t.right); } } class TestAVL { public static void main(String[] args) { { AVL a = null; for (int i = 0; i < 100; i++) { a = AVL.add(a, i); assert AVL.isAVL(a); System.out.println(a); System.out.println(AVL.height(a)); } } System.exit(0); Queue<Integer> l = new LinkedList<Integer>(); for (int len = 0; len < 100; len++) { for (int i = 0; i < len; i++) l.add(i); System.out.print(l.size() + " "); AVL a = AVL.ofList(l); System.out.println(AVL.height(a)); } Queue<Integer> l1 = new LinkedList<Integer>(); Queue<Integer> l2 = new LinkedList<Integer>(); for (int i = 0; i < 100; i++) { if (i % 2 == 0) l1.add(i); else l2.add(i); } AVL a = AVL.union(AVL.ofList(l1), AVL.ofList(l2)); assert AVL.isAVL(a); assert AVL.size(a) == 100; System.out.println("TESTAVL OK"); } } // encapsulation dans une structure mutable avec méthodes dynamiques public class AVLSet implements intf.Set<Integer> { private AVL root; private int size; public AVLSet() { this.root = null; } public boolean isEmpty() { return this.root == null; } public void clear() { this.root = null; this.size = 0; } public boolean contains(Integer x) { return AVL.contains(this.root, x); } public void add(Integer x) { if (!AVL.contains(this.root, x)) this.size++; this.root = AVL.add(this.root, x); } public int getMin() { return AVL.getMin(this.root); } public void removeMin() { if (isEmpty()) throw new IllegalArgumentException(); this.size--; this.root = AVL.removeMin(this.root); } public void remove(Integer x) { if (AVL.contains(this.root, x)) this.size--; this.root = AVL.remove(this.root, x); } public List<Integer> toList() { return AVL.toList(this.root); } public int size() { return this.size; } public boolean check() { return AVL.isAVL(this.root); } } class TestAVLSet { public static void main(String[] args) { AVLSet s = new AVLSet(); for (int i = 0; i < 10; i++) { assert s.size() == i; assert !s.contains(i); s.add(i); assert s.contains(i); assert s.check(); } for (int i = 0; i < 10; i++) { assert s.contains(i); assert s.getMin() == i; s.remove(i); assert i == 9 || s.getMin() == i+1; assert !s.contains(i); assert s.check(); } s.clear(); assert s.size() == 0; for (int i = 0; i < 100; i++) { int x = (int)(Math.random() * 100); s.add(x); assert s.contains(x); assert s.size() <= i+1; assert s.check(); } System.out.println("TestAVLSet OK"); } }