package common; import java.lang.reflect.Array; import java.util.*; /** * Class SkipList implements a skip list that uses int primitives for * the element keys. The modification methods defined by Set * are not supported. Instead, methods with keys are required. Note that * the keys have a many to one relationship with the elements (that is, * a range of key values will map to a single element). * *

Note that this implementation is not synchronized. If multiple * threads access a set concurrently, and at least one of the threads modifies * the set, it must be synchronized externally. This is typically * accomplished by synchronizing on some object that naturally encapsulates * the set. If no such object exists, the set should be "wrapped" using the * Collections.synchronizedList method. This is best done at * creation time, to prevent accidental unsynchronized access to the set:

*
 *     List l = Collections.synchronizedList(new DisjointSet(...));
 *
* *

The Iterators returned by this class's iterator method are * fail-fast: if the set is modified at any time after the iterator is * created, in any way except through the iterator's own remove * method, the iterator will throw a ConcurrentModificationException. * Thus, in the face of concurrent modification, the iterator fails quickly * and cleanly, rather than risking arbitrary, non-deterministic behavior at * an undetermined time in the future.

* * @author Original version: Nathan Fiedler (2001) * @author Several important bugfixes: Holger Hoffstaette * * @version $Revision$ $Date$ */ public class SkipList extends Object implements Set, Iterable { /** Optimal probability of most skip lists. */ public static final double OPTIMAL_P = 0.25; // MaxLevel = L(N) (where N is an upper bound on the number of // elements in a skip list). If p = 0.5, using MaxLevel = 16 is // appropriate for data structures containing up to 2^16 elements. /** Maximum level of any SkipList instance. */ protected final int MAX_LEVEL; /** Probability value for this skip list. */ protected final double P; /** Tail of this skip list. */ protected final SkipListElement _NIL; /** The level of this skip list. */ protected int _listLevel; /** Header is an element with no data. */ protected SkipListElement _listHeader; /** Number of elements in this skip list. */ protected int _elementCount; /** Increments each time the list changes. */ protected int _modCount; /** * Constructs an empty SkipList using the default probability * and maximum element size. */ public SkipList() { this(OPTIMAL_P, (int)Math.ceil(Math.log(Integer.MAX_VALUE) / Math.log(1 / OPTIMAL_P)) - 1); } /** * Constructs an empty SkipList object using the given probability * and maximum level. * * @param probability skip list probability value. * @param maxLevel maximum skip list level. */ public SkipList(double probability, int maxLevel) { P = probability; MAX_LEVEL = maxLevel; // Header is the root of our skip list. _listHeader = new SkipListElement(MAX_LEVEL, Integer.MIN_VALUE, null); // Allocate NIL with a key greater than any valid key; // all levels of skip lists terminate on NIL. _NIL = new SkipListElement(0, Integer.MAX_VALUE, null); this.clear(); } public SkipList(Collection c) { this(); this.addAll(c); } public boolean add(T o) { this.insert(o.hashCode(), o); return true; } public boolean addAll(Collection c) { boolean added = false; if (!c.isEmpty()) { for (Iterator iter = c.iterator(); iter.hasNext();) { added |= this.add(iter.next()); } } return added; } public void clear() { // List level is started at one. _listLevel = 1; // All forward pointers of list's header point to NIL. for (int i = _listHeader._forward.length - 1; i >= 0; i--) { _listHeader._forward[i] = _NIL; } // Reset element count. _elementCount = 0; _modCount++; } public boolean contains(Object o) { for (SkipListElement e = _listHeader._forward[0]; e != _NIL; e = e._forward[0]) { if ((e._value == o) || e._value != null && e._value.equals(o)) { return true; } } return false; } public boolean containsAll(Collection c) { if ((this.size() < c.size()) || (this.isEmpty() && c.isEmpty())) { return false; } for (Iterator iter = c.iterator(); iter.hasNext();) { if (!this.contains(iter.next())) { return false; } } return true; } /** * Removes the element with the given key from the list. * * @param searchKey key of element to remove. * @return true if element was found and removed. */ public boolean remove(int searchKey) { SkipListElement[] update = new SkipListElement[MAX_LEVEL]; SkipListElement e = _listHeader; for (int i = _listLevel; i >= 0; i--) { while (e._forward[i]._key < searchKey) { e = e._forward[i]; } update[i] = e; } e = e._forward[0]; if (e._key == searchKey) { for (int i = 0; i < _listLevel; i++) { if (update[i]._forward[i] != e) { break; } update[i]._forward[i] = e._forward[i]; } while (_listLevel > 0 && _listHeader._forward[_listLevel] == _NIL) { _listLevel--; } _elementCount--; _modCount++; return true; } return false; } /** * Inserts the element using the given search key. If an element * with the same key already exists in the skip lists, its value * will be replaced with newValue. * * @param searchKey key for element. * @param newValue new element to insert. */ @SuppressWarnings("unchecked") public void insert(int searchKey, T newValue) { SkipListElement[] update = new SkipListElement[MAX_LEVEL]; SkipListElement e = _listHeader; for (int i = _listLevel - 1; i >= 0; i--) { while (e._forward[i]._key < searchKey) { e = e._forward[i]; } update[i] = e; } e = e._forward[0]; if (e._key == searchKey) { e._value = newValue; } else { int lvl = randomLevel(); if (lvl > _listLevel) { for (int i = _listLevel; i <= lvl; i++) { update[i] = _listHeader; } _listLevel = lvl; } e = new SkipListElement(lvl, searchKey, newValue); for (int i = 0; i < lvl; i++) { e._forward[i] = update[i]._forward[i]; update[i]._forward[i] = e; } } _elementCount++; _modCount++; } public boolean isEmpty() { return (_elementCount == 0); } public Iterator iterator() { return new SkipListIterator(); } /** * Return a random level. * * @return level selected randomly. */ protected int randomLevel() { int lvl = 1; while (lvl < MAX_LEVEL && Math.random() < P) { lvl++; } return lvl; } public boolean remove(Object o) { return this.remove(o.hashCode()); } public boolean removeAll(Collection c) { boolean removed = false; for (Iterator iter = c.iterator(); iter.hasNext();) { removed |= this.remove(iter.next()); } return removed; } public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } /** * Searches for the element with the given key. * * @param searchKey key to look for. * @return element if found, null if not found. Note that you may * not want to store nulls in this list as it would then * be difficult to know the difference. */ public T get(int searchKey) { SkipListElement e = _listHeader; for (int i = _listLevel - 1; i >= 0; i--) { while (e._forward[i]._key < searchKey) { e = e._forward[i]; } } e = e._forward[0]; if (e._key == searchKey) { return e._value; } else { return null; } } /** * Searches for the element with a key that is the least smaller * value of the given key. * * @param searchKey key to look for. * @return element if found, null if not found. */ public T searchLeastSmaller(int searchKey) { SkipListElement e = _listHeader; for (int i = _listLevel - 1; i >= 0; i--) { while (e._forward[i]._key < searchKey) { e = e._forward[i]; } } if (e._forward[0]._key == searchKey) { return e._forward[0]._value; } else { return e._value; } } /** * Searches for the element just after the one found using the * given key (where the key value may be the least smaller of * the given key). * * @param searchKey key to look for. * @return next element if found, null if not found. */ public T searchNextLarger(int searchKey) { SkipListElement e = _listHeader; for (int i = _listLevel - 1; i >= 0; i--) { while (e._forward[i]._key < searchKey) { e = e._forward[i]; } } SkipListElement t = null; if (e._forward[0]._key == searchKey) { t = e._forward[0]; } else { t = e; } if (t._forward[0] == _NIL) { return null; } else { return t._forward[0]._value; } } /** * Returns the number of elements in this list. If this list contains * more than Integer.MAX_VALUE elements, returns * Integer.MAX_VALUE. * * @return the number of elements in this list. */ public int size() { return _elementCount; } /** * Returns an array containing all of the elements in this list in * proper sequence. Obeys the general contract of the * Collection.toArray() method. * * @return an array containing all of the elements in this list in * proper sequence. * @see Arrays#asList(Object[]) */ public Object[] toArray() { return toArray(new Object[_elementCount]); } /** * Returns an array containing all of the elements in this list in * proper sequence; the runtime type of the returned array is that * of the specified array. Obeys the general contract of the * Collection.toArray(Object[]) method. * * @param a the array into which the elements of this list are to * be stored, if it is big enough; otherwise, a new array * of the same runtime type is allocated for this purpose. * @return an array containing the elements of this list. * @exception ArrayStoreException * Throw if the runtime type of the specified array is not * a supertype of the runtime type of every element in this * list. */ @SuppressWarnings({"unchecked","hiding"}) public T[] toArray(T[] a) { int size = this.size(); if (a.length < size) { a = (T[])Array.newInstance(a.getClass().getComponentType(), size); } SkipListElement e = _listHeader; for (int i = 0; i < _elementCount; i++) { a[i] = (T)e._forward[0]._value; e = e._forward[0]; } return a; } /** * Class Element represents an element of a skip list. */ protected class SkipListElement extends Object { /** Key of element. */ int _key; /** Value of element. */ E _value; /** List of forward pointers. */ SkipListElement[] _forward; /** * Constructs an Element for the given key and value. * * @param level level for this node (number of forward pointers). * @param key key for element. * @param value value for element. */ @SuppressWarnings("unchecked") public SkipListElement(int level, int key, E value) { _key = key; _value = value; _forward = new SkipListElement[level]; } } /** * An iterator over a skip list. */ protected class SkipListIterator implements Iterator { /** Index into the skip list. */ protected int _index; /** The modCount of the list at the time we were instantiated. */ protected int _listModCount; /** Current element being examined. */ protected SkipListElement _elem; /** * Constructs a skip list iterator. */ public SkipListIterator() { _listModCount = SkipList.this._modCount; _elem = _listHeader; } /** * Returns true if the iteration has more elements. (In * other words, returns true if next would return * an element rather than throwing an exception.) * * @return true if the iterator has more elements. */ public boolean hasNext() { if (this._listModCount != SkipList.this._modCount) { throw new ConcurrentModificationException(); } return _elem._forward[0] != _NIL; } /** * Returns the next element in the iteration. * * @return the next element in the iteration. * @exception NoSuchElementException * iteration has no more elements. */ public T next() { if (this._listModCount != SkipList.this._modCount) { throw new ConcurrentModificationException(); } if (this.hasNext()) { _elem = _elem._forward[0]; return _elem._value; } else { throw new NoSuchElementException(); } } public void remove() { throw new UnsupportedOperationException(); } } }