import java.util.NoSuchElementException; public class BinarySearchTree implements SortedMap { private Branch root = null; private int length = 0; private Comparator comparator = null; public BinarySearchTree( Comparator c ) { comparator = c; } public BinarySearchTree() { this( null ); } public void clear() { root = null; length = 0; } public boolean isEmpty() { return ( root == null ); } public int size() // devuelve el número de elementos del mapa { return length; } public Object firstKey() // devuelve la clave del primer elemento; // es null si el mapa está vacío { if ( root == null ) return null; else return root.first().key; } public Object lastKey() // devuelve la clave del último elemento; // es null si el mapa está vacío { if ( root == null ) return null; else return root.last().key; } public Object get( Object k ) // devuelve el valor correspondiente a la clave k // si ésta está en el árbol; de lo contrario, es null { Branch b = find( k ); return ( b == null ) ? null : b.value; } public Object put(Object k, Object v) // si ya hay un nodo correspondiente a // k devuelve su valor y los sustituye por v; // de lo contrario, inserta un nuevo nodo(k, v) { Branch p = null; Branch b = root; int c = 0; // encuentra el nodo con clave k y conserva la referencia p al padre while ( b != null ) { p = b; c = compare( k, b.key ); if ( c == 0 ) { // lo ha encontrado; inserta el nuevo valor y devuelve el antiguo Object oldValue = b.value; b.value = v; return oldValue; } else if ( c < 0 ) b = b.left; else b = b.right; } // La clave k no existe en el árbol; inserta un nuevo nodo debajo de p(adre) Branch newBranch = new Branch( k, v, p ); length++; if ( p == null ) { root = newBranch; } else { // c sigue conservando el resultado de la comparación que nos condujo al punto de inserción if ( c < 0 ) p.left = newBranch; else p.right = newBranch; } return null; } public Object remove( Object k) // elimina el nodo correspondiente a la clave k // si éste está en el árbol y devuelve el valor; // de lo contrario, devuelve null { Branch b = find( k ); if ( b == null ) return null; else { delete( b ); return b.value; } } public MapIterator iterator() { return new TreeIterator(); } private Branch find( Object k ) { Branch b = root; int c; while ( b != null && ( c = compare( k, b.key )) != 0 ) { if ( c < 0 ) b = b.left; else b = b.right; } return b; } private void delete( Branch b ) { Branch toBeSpliced = null; // nodo para dividir; // = cualquier nodo para eliminar // o un nodo para desplazar y sustituir al eliminado Object ret = null; length--; if ( b.left == null || b.right == null ) // el nodo que se va a eliminar tiene, al menos, un hijo toBeSpliced = b; else // el nodo que se va a eliminar tiene dos hijos // se sustituye por su sucesor toBeSpliced = b.first(); // determina qué hijo se agregará al padre del nodo eliminado Branch newChild = ( toBeSpliced.left != null ) ? toBeSpliced.left : toBeSpliced.right; if ( newChild != null ) newChild.parent = toBeSpliced.parent; if ( toBeSpliced.parent == null ) root = newChild; else { // se agrega un nuevo hijo a la rama toBeSpliced de la que provenía if ( toBeSpliced == toBeSpliced.parent.left ) toBeSpliced.parent.left = newChild; else toBeSpliced.parent.right = newChild; } if ( toBeSpliced != b ) { // = caso en que toBeSpliced se desplaza, no se elimina toBeSpliced.parent = b.parent; toBeSpliced.left = b.left; toBeSpliced.right = b.right; } } private int compare(Object k1, Object k2) { if ( k1 == null || k2 == null ) throw new IllegalArgumentException( "Null key now allowed" ); // si hay un comparadro, se utiliza if ( comparator != null ) return comparator.compare( k1, k2 ); else { return ((Comparable)k1).compareTo(k2); } } static private class Branch { private Branch left = null; private Branch right = null; private Branch parent = null; private Object key; private Object value = null; Branch( Object k, Object v, Branch p ) { key = k; value = v; parent = p; } Branch( Object k, Object v ) { this( k, v, null ); } Branch( Object k ) { this( k, null, null ); } Branch first() { Branch f = this; while ( f.left != null ) { f = f.left; } return f; } Branch last() { Branch l = this; while ( l.right != null ) { l = l.right; } return l; } Branch successor() { // si hay un hijo a la derecha, el sucesor es el método first() del hijo de la derecha if ( right != null ) return right.first(); /* * De lo contrario, busca el primer antecesor para el que es válida la ruta al actual * a través del hijo de la izquierda. */ Branch pp = parent; Branch p = this; while ( pp != null && p == pp.right ) { p = pp; pp = pp.parent; } return pp; } } public class TreeIterator implements MapIterator { private Branch current = null; private Branch next; public TreeIterator() { next = ( root == null ) ? null : root.first(); } public boolean hasNext() { return next != null; } public Object next() throws NoSuchElementException { if ( next == null ) throw new NoSuchElementException(); current = next; next = current.successor(); return current.key; } public Object remove() throws IllegalStateException { if ( current == null ) throw new IllegalStateException(); delete( current ); Object ret = current.value; current = null; return ret; } public Object key() throws IllegalStateException { if ( current == null ) throw new IllegalStateException(); return current.key; } public Object getValue() throws IllegalStateException { if ( current == null ) throw new IllegalStateException(); return current.value; } public Object setValue( Object v ) throws IllegalStateException { if ( current == null ) throw new IllegalStateException(); Object ret = current.value; current.value = v; return ret; } } }