package jtrade.util;
import java.util.Arrays;
import java.util.Iterator;
public class DoubleSkipList implements Iterable<Double> {
private static final double LOG_2 = Math.log(2);
int count;
int maxLevels;
Node head;
public DoubleSkipList() {
this(100);
}
public DoubleSkipList(int expectedSize) {
maxLevels = (int) (1.0 + Math.log(expectedSize) / LOG_2);
head = new Node(maxLevels, Double.NaN);
}
public int size() {
return count;
}
public boolean isEmpty() {
return count == 0;
}
public void clear() {
head = new Node(maxLevels, Double.NaN);
count = 0;
}
public double get(int index) {
if (index >= count || index < 0) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + count);
}
Node node = head;
index++;
for (int l = maxLevels - 1; l >= 0; l--) {
while (node.width[l] <= index) {
index -= node.width[l];
node = node.next[l];
}
}
return node.value;
}
public void add(double value) {
// find first node on each level where node.next[levels].value > value
Node[] update = new Node[maxLevels];
int[] stepsAtLevel = new int[maxLevels];
Node node = head;
for (int l = maxLevels - 1; l >= 0; l--) {
while (node.next[l] != null && node.next[l].value <= value) {
stepsAtLevel[l] += node.width[l];
node = node.next[l];
}
update[l] = node;
}
// insert a link to the new node at each level
int d = randomLevel();
Node newNode = new Node(d, value);
int steps = 0;
for (int l = 0; l < d; l++) {
Node prevNode = update[l];
newNode.next[l] = prevNode.next[l];
prevNode.next[l] = newNode;
newNode.width[l] = prevNode.width[l] - steps;
prevNode.width[l] = steps + 1;
steps += stepsAtLevel[l];
}
for (int level = d; level < maxLevels; level++) {
update[level].width[level] += 1;
}
count++;
}
public boolean contains(double value) {
// find first node on each level where node.next[levels].value > value
Node[] update = new Node[maxLevels];
Node node = head;
for (int l = maxLevels - 1; l >= 0; l--) {
while (node.next[l] != null && node.next[l].value < value) {
node = node.next[l];
}
update[l] = node;
}
return value == update[0].next[0].value;
}
public boolean remove(int index) {
return remove(get(index));
}
public boolean remove(double value) {
// find first node on each level where node.next[levels].value >= value
Node[] update = new Node[maxLevels];
Node node = head;
for (int l = maxLevels - 1; l >= 0; l--) {
while (node.next[l] != null && node.next[l].value < value) {
node = node.next[l];
}
update[l] = node;
}
node = update[0].next[0];
if (node.value != value) {
return false;
}
int d = node.levels();
for (int l = 0; l < d; l++) {
Node prevNode = update[l];
prevNode.width[l] += prevNode.next[l].width[l] - 1;
prevNode.next[l] = prevNode.next[l].next[l];
}
for (int l = d; l < maxLevels; l++) {
update[l].width[l]--;
}
count--;
return true;
}
@Override
public String toString() {
return Arrays.toString(toArray());
}
public double[] toArray() {
if (count == 0) {
return new double[0];
}
double[] array = new double[count];
int i = 0;
Node next = head.next[0];
while (next != null) {
array[i++] = next.value;
next = next.next[0];
}
return array;
}
@Override
public Iterator<Double> iterator() {
return new Iterator<Double>() {
Node next = head.next[0];
Node curr = null;
@Override
public boolean hasNext() {
return next != null;
}
@Override
public Double next() {
curr = next;
next = next.next[0];
return curr.value;
}
@Override
public void remove() {
DoubleSkipList.this.remove(curr.value);
}
};
}
private int randomLevel() {
return Math.min(maxLevels, 1 - (int) (Math.log(Math.random()) / LOG_2));
}
class Node {
Node[] next;
int[] width;
double value;
Node(int levels, double value) {
next = new Node[levels];
width = new int[levels];
for (int i = 0; i < width.length; i++) {
width[i] = 1;
}
this.value = value;
}
int levels() {
return next.length;
}
}
public static void main2(String[] args) {
DoubleSkipList ss = new DoubleSkipList();
while (true) {
ss.add(Math.random());
if (ss.size() > 100) {
ss.remove(ss.size() / 2);
}
}
}
public static void main(String[] args) {
DoubleSkipList ss = new DoubleSkipList();
ss.add(5);
ss.add(10);
ss.add(7);
ss.add(7);
ss.add(6);
System.out.println(ss.size());
System.out.println(ss.get(ss.size() / 2));
if (ss.contains(7)) {
System.out.println("7 is in the list");
}
ss.remove(Double.NaN);
System.out.println(ss);
ss.remove(2);
System.out.println(ss);
ss.remove(7.0);
System.out.println(ss);
if (!ss.contains(7)) {
System.out.println("7 has been deleted");
}
System.out.println(ss.size());
System.out.println(ss.get(ss.size() / 2));
ss.clear();
System.out.println(ss);
}
}