import java.util.*; public class SkipList { public static class Entry { public String key; public Integer value; public int pos; // For printing purpose... public Entry(String k, Integer v) { key = k; value = v; } } public static class HashEntry { public Entry x; public HashEntry up, down, left, right; public static String negInf = new String("-oo"); // -inf key value public static String posInf = new String("+oo"); // +inf key value public HashEntry(String k, Integer v) { x = new Entry(k, v); up = down = left = right = null; } public HashEntry(Entry e) { x = e; up = down = left = right = null; } public Integer getValue() { return x.value; } public String getKey() { return x.key; } public Integer setValue(Integer val) { Integer oldValue = x.value; x.value = val; return oldValue; } public boolean equals(Object o) { HashEntry ent; try { ent = (HashEntry) o; // Test if o is a HashEntry... } catch (ClassCastException ex) { return false; } return (ent.getKey() == x.key) && (ent.getValue() == x.value); } public String toString() { return "(" + x.key + "," + x.value + ")"; } } public HashEntry head; // First element of the top level public HashEntry tail; // Last element of the top level public int n; // number of entries in the dictionary public int h; // Height public Random r; // Coin toss /* ---------------------------------------------- Constructor: empty skiplist null null ^ ^ | | head ---> null <-- -inf <----> +inf --> null | | v v null null ---------------------------------------------- */ public SkipList() // Default constructor... { HashEntry p1, p2; p1 = new HashEntry(HashEntry.negInf, null); p2 = new HashEntry(HashEntry.posInf, null); head = p1; tail = p2; p1.right = p2; p2.left = p1; n = 0; h = 0; r = new Random(); } /** Returns the number of entries in the hash table. */ public int size() { return n; } /** Returns whether or not the table is empty. */ public boolean isEmpty() { return (n == 0); } /* ------------------------------------------------------ findEntry(k): find the largest key x <= k on the LOWEST level of the Skip List ------------------------------------------------------ */ public HashEntry findEntry(String k) { HashEntry p; /* ----------------- Start at "head" ----------------- */ p = head; // System.out.println(">>>> " + p.x.key); while ( true ) { /* -------------------------------------------- Search RIGHT until you find a LARGER entry -------------------------------------------- */ while ( p.right.x.key != HashEntry.posInf && k.compareTo(p.right.x.key) >= 0 ) { p = p.right; // System.out.println(">> " + p.x.key); } // System.out.println("|| " + p.right.x.key); /* --------------------------------- Go down one level if you can... --------------------------------- */ if ( p.down != null ) { p = p.down; // System.out.println("VV " + p.x.key); } else break; // We reached the LOWEST level... Exit... } return(p); // Nearest p (<= k) } /** Returns the value associated with a key. */ public Integer get (String k) { HashEntry p; p = findEntry(k); if ( k.equals( p.x.key ) ) return(p.x.value); else return(null); } /* ------------------------------------------- insertAfterAbove(p, q, y=(k,v) ) 1. create new entry (k,v) 2. insert (k,v) AFTER p 3. insert (k,v) ABOVE q q.up ^ | v p <--> (k,v) <--> p.right ^ | v q NOTE: p can be null ! ------------------------------------------- */ public HashEntry insertAfterAbove( HashEntry p, HashEntry q, Entry y) { HashEntry e; e = new HashEntry(y); /* --------------------------------------- Use the links before they are changed ! --------------------------------------- */ e.left = p; if ( p != null ) e.right = p.right; else e.right = null; e.down = q; if ( q != null ) e.up = q.up; else e.up = null; /* --------------------------------------- Now update the existing links.. --------------------------------------- */ if ( p != null && p.right != null ) p.right.left = e; if ( p != null ) p.right = e; if ( q != null && q.up != null ) q.up.down = e; if ( q != null ) q.up = e; return(e); } /** Put a key-value pair in the map, replacing previous one if it exists. */ public Integer put (String k, Integer v) { HashEntry p, q; Entry e; int i; p = findEntry(k); // System.out.println("findEntry(" + k + ") returns: " + p.x.key); /* ------------------------ Check if key is found ------------------------ */ if ( k.equals(p.x.key) ) { Integer old = p.x.value; p.x.value = v; return(old); } /* ------------------------ Insert new entry (k,v) ------------------------ */ e = new Entry(k, v); /* ------------------------------------------------------ **** BUG: He forgot to insert in the lowest level !!! Link at the lowest level ------------------------------------------------------ */ q = new HashEntry(e); q.left = p; q.right = p.right; p.right.left = q; p.right = q; i = -1; while ( r.nextDouble() < 0.5 ) { i = i + 1; // System.out.println("i = " + i + ", h = " + h ); if ( i >= h ) { HashEntry p1, p2; /* ----------------------- Make a new level ----------------------- */ h = h + 1; p1 = new HashEntry(HashEntry.negInf,null); p2 = new HashEntry(HashEntry.posInf,null); p1.right = p2; p1.down = head; p2.left = p1; p2.down = tail; head.up = p1; tail.up = p2; head = p1; tail = p2; /* head = insertAfterAbove( null, head, new Entry(HashEntry.negInf,null) ); insertAfterAbove(head, tail, new Entry(HashEntry.posInf, null) ); */ } /* ------------------------- Scan backwards... ------------------------- */ while ( p.up == null ) { // System.out.print("."); p = p.left; } // System.out.print("1 "); p = p.up; q = insertAfterAbove( p, q, e ); // System.out.println("2"); } n = n + 1; // System.out.println("3"); return(null); // No old value } /** Removes the key-value pair with a specified key. */ public Integer remove (String key) { return(null); } public void printHorizontal() { String s = ""; int i; HashEntry p; /* ---------------------------------- Record the position of each entry ---------------------------------- */ p = head; while ( p.down != null ) { p = p.down; } i = 0; while ( p != null ) { p.x.pos = i++; p = p.right; } /* ------------------- Print... ------------------- */ p = head; while ( p != null ) { s = getOneRow( p ); System.out.println(s); p = p.down; } } public String getOneRow( HashEntry p ) { String s; int a, b, i; a = 0; s = "" + p.x.key; p = p.right; while ( p != null ) { HashEntry q; q = p; while (q.down != null) q = q.down; b = q.x.pos; s = s + " <-"; for (i = a+1; i < b; i++) s = s + "--------"; s = s + "> " + p.x.key; a = b; p = p.right; } return(s); } public void printVertical() { String s = ""; HashEntry p; p = head; while ( p.down != null ) p = p.down; while ( p != null ) { s = getOneColumn( p ); System.out.println(s); p = p.right; } } public String getOneColumn( HashEntry p ) { String s = ""; while ( p != null ) { s = s + " " + p.x.key; p = p.up; } return(s); } }