package com.jwetherell.algorithms.data_structures; import java.util.Random; import com.jwetherell.algorithms.data_structures.interfaces.ISet; /** * Skip List. A skip list is a data structure for storing a sorted list of items * using a hierarchy of linked lists that connect increasingly sparse * subsequences of the items. These auxiliary lists allow item lookup with * efficiency comparable to balanced binary search trees. * * http://en.wikipedia.org/wiki/Skip_list * * @author Justin Wetherell */ @SuppressWarnings("unchecked") public class SkipList> implements ISet { private static final Random seedGenerator = new Random(); // If you change this number, you also need to change the random function. private static final int MAX = 31; private INodeCreator creator = null; private int randomSeed = -1; private int size = 0; protected Node head = null; public SkipList() { randomSeed = seedGenerator.nextInt() | 0x0100; } public SkipList(INodeCreator creator) { this(); this.creator = creator; } /** * Returns a random level for inserting a new node. * Hardwired to k=1, p=0.5, max 31 */ private int getRandom() { int x = randomSeed; x ^= x << 13; x ^= x >>> 17; randomSeed = x ^= x << 5; if ((x & 0x8001) != 0) // test highest and lowest bits return 0; int level = 1; while (((x >>>= 1) & 1) != 0) ++level; return level; } protected Node addValue(T value) { Node toReturn = null; if (head==null) { // new list Node node = null; if (creator==null) node = new Node(MAX,value); else node = creator.createNewNode(MAX, value); head = node; toReturn = node; } else { int level = getRandom(); Node node = null; if (creator==null) node = new Node(level,value); else node = creator.createNewNode(level, value); Node prev = head; if (head.data.compareTo(value)>0) { // handle case where head is greater than new node, just swap values //T oldHeadValue = head.data; //head.data = value; // Swap the old head value into the new node //node.data = oldHeadValue; if (creator==null) swapNode(node,head); else creator.swapNode(node, head); toReturn = head; } else { toReturn = node; } // Start from the top and work down to update the pointers for (int i=MAX; i>=0; i--) { Node next = prev.getNext(i); while (next!=null) { if (next.data.compareTo(value)>0) break; prev = next; // It's important to set next since the node we are looking for // on the next level cannot be behind this "prev" node. next = prev.getNext(i); } if (i <= level) { // If we are on a level where the new node exists, update the linked list node.setNext(i, next); prev.setNext(i, node); } } } size++; return toReturn; } /** * {@inheritDoc} */ @Override public boolean add(T value) { Node node = addValue(value); return (node!=null); } private NodeLevelPair getPredecessor(T value) { Node node = head; if (node==null) return null; if (node.data.compareTo(value)==0) return null; // Current node is not the node we are looking for; Keep moving down // until you find a node with a non-null "next" pointer. int level = node.getLevel(); Node next = node.getNext(level); while (next==null) { // If next is null, move down if (level>0) next = node.getNext(--level); else break; } // Found a node with a next node OR I reached the bottom level while (next!=null) { int comp = next.data.compareTo(value); if (comp==0) { // Found the node who's next node is the node we are looking for! NodeLevelPair pair = new NodeLevelPair(level,node); return pair; } else if (comp>=1) { // Found a node that's greater, move down a level if (level>0) level--; else return null; // Update the next pointer next = node.getNext(level); } else { // Next is less then the value we are looking for, keep moving to next. node = next; next = node.getNext(level); while (next==null && level>0) { next = node.getNext(--level); } } } return null; } protected Node getNode(T value) { if (head==null) return null; if (head.data.compareTo(value)==0) return head; NodeLevelPair pair = getPredecessor(value); if (pair==null) return null; return pair.node.getNext(pair.level); } protected void swapNode(Node node, Node next) { T value = node.data; node.data = next.data; next.data = value; } protected Node removeValue(T value) { if (head==null) return null; Node node = null; Node prev = null; int lvl = 0; if (head.data.compareTo(value)==0) { node = head; } else { // Find the predecessor of the node we are looking for and // which level it is found on. NodeLevelPair pair = getPredecessor(value); if (pair!=null) { prev = pair.node; lvl = pair.level; } // Cannot find predecessor of value if (prev == null) return null; // Use predecessor to get actual node node = prev.getNext(lvl); // Node doesn't exist if (node == null || node.data.compareTo(value)!=0) return null; } Node next = null; // Head node is the only node without a prev node if (prev == null) { next = node.getNext(0); // Removing head if (next != null) { // Switch the value of the next into the head node if (creator==null) swapNode(node,next); else creator.swapNode(node, next); // Update the prev and node pointer prev = node; node = next; } else { // If head doesn't have a new node then list is empty head = null; } } else { // Set the next node pointer next = node.getNext(lvl); } // Start from the top level and move down removing the node int level = node.getLevel(); for (int i=level; i>=0; i--) { next = node.getNext(i); if (prev!=null) { prev.setNext(i, next); if (i > 0) { // Move down a level and look for the 'next' previous node Node temp = prev.getNext(i - 1); while (temp != null && temp.data.compareTo(value) != 0) { prev = temp; temp = temp.getNext(i - 1); } } } } size--; return node; } /** * {@inheritDoc} */ @Override public boolean remove(T value) { Node node = removeValue(value); return (node!=null); } /** * {@inheritDoc} */ @Override public void clear() { head = null; size = 0; } /** * {@inheritDoc} */ @Override public boolean contains(T value) { return (getNode(value)!=null); } /** * {@inheritDoc} */ @Override public int size() { return size; } /** * {@inheritDoc} */ @Override public boolean validate() { if (head==null) return true; int level = MAX; for (int i=level; i>=0; i--) { Node prev = head; Node node = prev.getNext(i); while (node != null) { // The list should be ordered if (node.data.compareTo(prev.data) < 1) return false; prev = node; node = prev.getNext(i); } } return true; } /** * {@inheritDoc} */ @Override public java.util.Set toSet() { return (new JavaCompatibleSkipList(this)); } /** * {@inheritDoc} */ @Override public java.util.Collection toCollection() { return (new JavaCompatibleSkipList(this)); } // Output a String version of the skip list. If a value and level is passed // then output with that node highlighted. public String getString(T value, int level) { StringBuilder builder = new StringBuilder(); builder.append("size=").append(size).append("\n"); Node node = head; if (node!=null) { int iLevel = node.getLevel(); for (int i=iLevel; i>=0; i--) { builder.append("[").append(i).append("] "); node = head; while (node != null) { if (level==i && value!=null && node.data.compareTo(value)==0) builder.append("(").append(node.data).append(")"); else builder.append(node.data); Node next = node.getNext(i); if (next != null) builder.append("->"); node = next; } if (i>0) builder.append("\n"); } } builder.append("\n"); return builder.toString(); } /** * {@inheritDoc} */ @Override public String toString() { return getString(null,-1); } protected static class Node> { private Node[] next = null; protected T data = null; protected Node(int level, T data) { this.next = new Node[level+1]; this.data = data; } protected int getLevel() { return next.length-1; } protected void setNext(int idx, Node node) { this.next[idx] = node; } protected Node getNext(int idx) { if (idx>=this.next.length) return null; return this.next[idx]; } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("data=").append(data); int size = next.length; if (next!=null) { builder.append("\n").append("next=["); for (int i=0; i n = next[i]; if (n!=null) builder.append(n.data); else builder.append("none"); if (i!=size-1) builder.append(", "); } builder.append("]"); } return builder.toString(); } } protected static interface INodeCreator> { /** * Create a new Node with the following parameters. * * @param level of this node. * @param data of this node. * @return new Node */ public Node createNewNode(int level, T data); /** * Swap the two nodes internals * * @param node to swap. * @param next to swap. */ public void swapNode(Node node, Node next); } private static final class NodeLevelPair> { private int level = -1; private Node node = null; private NodeLevelPair(int level, Node node) { this.level = level; this.node = node; } } public static class JavaCompatibleSkipList> extends java.util.AbstractSet { private SkipList list = null; public JavaCompatibleSkipList(SkipList list) { this.list = list; } /** * {@inheritDoc} */ @Override public boolean add(T value) { return list.add(value); } /** * {@inheritDoc} */ @Override public boolean remove(Object value) { return list.remove((T)value); } /** * {@inheritDoc} */ @Override public boolean contains(Object value) { return list.contains((T)value); } /** * {@inheritDoc} */ @Override public int size() { return list.size(); } /** * {@inheritDoc} */ @Override public java.util.Iterator iterator() { return (new SkipListListIterator(list)); } private static class SkipListListIterator> implements java.util.Iterator { private SkipList list = null; private SkipList.Node next = null; private SkipList.Node last = null; private SkipListListIterator(SkipList list) { this.list = list; this.next = list.head; } /** * {@inheritDoc} */ @Override public void remove() { if (last==null) return; list.remove(last.data); } /** * {@inheritDoc} */ @Override public boolean hasNext() { return (next!=null); } /** * {@inheritDoc} */ @Override public T next() { if (next == null) throw new java.util.NoSuchElementException(); last = next; next = next.getNext(0); return last.data; } } } }