import java.util.*; public class Tree24 { /* ================================================= Variables ================================================= */ public Node root; public Node searchEndPos; // Last node visited by findEntry() /* ================================================= Constructor ================================================= */ public Tree24() { root = null; } /* ============================================================ keySearch(k): find entry containing key k Return value: if ( smone e[i].key == k ) then return( e[i] ) else return ( null ); searchEndPos = node last visited in search ============================================================ */ public Entry keySearch(String k) { int i; Node curr; // System.out.println("enter keySearch(" + k + ")"); searchEndPos = root; curr = root; while ( curr != null ) { for (i = 0; i < 3; i++) { /* --------------------------------------------------------- Check if: k < e[i].key, if so: go to subtree child[i] Notice the order: child[0] e[0] .... child[i] e[i] child[i+1] e[i+1]... --------------------------------------------------------- */ // System.out.println("i = "+i); if ( curr.e[i] != null && k.compareTo( curr.e[i].key ) < 0 ) { if ( curr.child[i] != null ) { // System.out.println("Search subtree "+i+" of node " + curr); searchEndPos = curr; curr = curr.child[i]; break; // end to for } } if ( curr.e[i] != null && k.compareTo( curr.e[i].key ) == 0 ) { return( curr.e[i] ); } if ( i == 2 || curr.e[i+1] == null ) // e[i] is last value key { // System.out.println("Search subtree "+i+" of node " + curr); searchEndPos = curr; curr = curr.child[i+1]; break; // end to for } } } // System.out.println("exit keySearch(" + k + ")"); return(null); // To make Java happy... } /* ================================================ get(k): return value associated with key k ================================================ */ Integer get(String k) { Entry e; e = keySearch(k); if ( e == null ) return(null); else return(e.value); } /* ================================================ put(k): insert (k,v) ================================================ */ Integer put(String k, Integer v) { Node p; Entry e; /* ------------------------ Special case: empty tree ------------------------ */ if ( root == null ) { p = new Node(); p.e[0] = new Entry(); p.e[0].key = k; p.e[0].value = v; root = p; p.parent = p; // Parent(root) == root return(null); } /* ------------------------ Other cases ------------------------ */ e = keySearch(k); // keySearch sets "searchEndPos = last node visited // System.out.println("Last node visited = "+searchEndPos); /* ------------------------ key found, update value ------------------------ */ if ( e != null && k.compareTo(e.key) == 0 ) { Integer oldValue; System.out.print("*** Update value of " + k + " in node " + searchEndPos); oldValue = e.value; e.value = v; return(oldValue); } /* ------------------------------------------ key not found: insert (k,v) in node "searchEndPos" ------------------------------------------ */ e = new Entry(k,v); insertEntryInThisNode(e, null, searchEndPos); return(null); } /* ======================================================= insertEntryInThisNode(e, rightSubTree, p): 1. insert "e" and its "rightSubTree" in node p 2. if over flow, split and insert in parent ======================================================= */ public void insertEntryInThisNode(Entry e, Node rightSubTree, Node p) { int i; Node q; if ( p.e[2] == null ) { /* ----------------- There is space ----------------- */ insertEntryDirectlyInNode(e, rightSubTree, p); } else { /* -------------------------------- There is no more space .... -------------------------------- */ System.out.print("*** Split insert !"); /* ================================== Make a virtual node with 4 keys ================================== */ Entry[] x_e = new Entry[4]; Node[] x_child = new Node[5]; x_child[0] = p.child[0]; i = 0; while ( i < 3 && p.e[i].key.compareTo(e.key) < 0 ) { x_e[i] = p.e[i]; x_child[i+1] = p.child[i+1]; i++; } /* ---------------------- Insert e at x_e[i] ---------------------- */ x_e[i] = e; x_child[i+1] = rightSubTree; while ( i < 3 ) { x_e[i+1] = p.e[i]; x_child[i+2] = p.child[i+1]; i++; } System.out.print(" ---- Transitional node = "); for (i=0; i<4; i++) { if ( i != 2 ) System.out.print( x_e[i].key + " "); else System.out.print( "(" + x_e[i].key + ") "); } System.out.println(); /* ================== Distribute keys ================== */ p.child[0] = x_child[0]; p.e[0] = x_e[0]; p.child[1] = x_child[1]; p.e[1] = x_e[1]; p.child[2] = x_child[2]; p.e[2] = null; p.child[3] = null; q = new Node(); q.child[0] = x_child[3]; q.e[0] = x_e[3]; q.child[1] = x_child[4]; if ( p == root ) { /* Split root */ Node newRoot = new Node(); newRoot.child[0] = p; newRoot.e[0] = x_e[2]; newRoot.child[1] = q; p.parent = newRoot; q.parent = newRoot; root = newRoot; } else { System.out.println("****** Recurse !"); q.parent = p.parent; insertEntryInThisNode(x_e[2], q, p.parent); } } } /* ======================================================= insertEntryDirectlyInNode(e, rightChild, p): Node p: e[2] == null for sure c[0] c[1] c[2] c[3] | | | | | | | | e[0] e[1] e[2] Let i = the proper entry Set: e[i] = e (Copy the child pointers also) ======================================================= */ public void insertEntryDirectlyInNode(Entry e, Node rightChild, Node p) { int i; System.out.println("Insert " + e.key + " in node " + p); /* ------------------------------------ Node p: c[0] c[1] c[2] c[3] | | | | | | | | e[0] e[1] e[2] e[2] == null for sure ------------------------------------ */ if ( p.e[1] == null || p.e[1].key.compareTo(e.key) > 0 ) { // System.out.println("Copy e[2] -> e[1]"); p.e[2] = p.e[1]; p.child[3] = p.child[2]; } else { // System.out.println("Insert " + e.key + " in entry 2 of" + p); p.e[2] = e; p.child[3] = rightChild; return; } if ( p.e[0] == null || p.e[0].key.compareTo(e.key) > 0 ) { // System.out.println("Copy e[1] -> e[0]"); p.e[1] = p.e[0]; p.child[2] = p.child[1]; } else { // System.out.println("Insert " + e.key + " in entry 1 of" + p); p.e[1] = e; p.child[2] = rightChild; return; } // System.out.println("Insert " + e.key + " in entry 0 of" + p); p.e[0] = e; p.child[1] = rightChild; if ( rightChild != null ) { rightChild.parent = p; } } /* ================================================= printTree() ================================================= */ void padding ( String s, int n ) { int i; for ( i = 0; i < n; i++ ) System.out.print( s ); } void printSub (Node p, int id, int level ) { int i; if ( p == null) return; if ( p.child[3] != null ) { printSub ( p.child[3], 3, level + 1 ); } if ( p.child[2] != null ) { printSub ( p.child[2], 2, level + 1 ); } if ( p.child[2] != null ) { padding( " ", level ); System.out.println("" + id + ":" + p); if ( p.child[1] != null ) { printSub ( p.child[1], 1, level + 1 ); } } else { if ( p.child[1] != null ) { printSub ( p.child[1], 1, level + 1 ); } padding( " ", level ); System.out.println("" + id + ":" + p); } if ( p.child[0] != null ) { printSub ( p.child[0], 0, level + 1 ); // System.out.println(); } } public void printTree() { printSub( root, 0, 0); } }