代码实现(只实现了新增,打印和判断是否存在)
public class SkipList {
private static class Node {
Integer key;
String value;
Node up = null, down = null, left = null, right = null;
public static Integer headKey = Integer.MIN_VALUE; // 跳表左界限
public static Integer tailKey = Integer.MAX_VALUE; // 跳表右界限
public Node(Integer key, String value) {
this.key = key;
this.value = value;
}
}
//头结点 (最高层)
private Node head;
//尾结点 (最高层)
private Node tail;
//跳表层数
private Integer level;
//元素数
private Integer size;
private Random random; //随机投掷硬币
private static final double PROBABILITY = 0.5;//向上提升一个的概率
{
head = new Node(Node.headKey, null);
tail = new Node(Node.tailKey, null);
size = 0;
head.right = tail;
tail.left = head;
random = new Random();
level = 0;
}
/**
* 判断是否存在此key
*
* @param key
* @return
*/
public Boolean contain(Integer key) {
Node node = find(key);
if (node.key.equals(key)) {
return true;
}
return false;
}
public void put(Integer key, String value) {
//找到插入位置的前一个节点(由于只有最后一层有数据域 所以find(key)查询的插入点 一定在最后一层)
Node p = find(key);
//已存在就不处理
if (p.key == key) {
return;
}
//往底层插入节点 所以不需要连接'down'
// 因为是刚插入的节点所以以前底层是没有此节点的,
// 根据跳跃表的特性底层没有该节点,上层肯定也没有,所以不需要连接'up'
Node newNode = new Node(key, value);
insertpre2aft(p, newNode);
Integer currentLevel = 0;
/*--------------至此跳表的元素插入以完成,接下来是跳表的底层元素向上提升-------------------*/
//抛硬币决定刚插入的元素 是否向上加提升
while (random.nextDouble() < PROBABILITY) {
//如果当前层数为最高层
if (currentLevel >= level) {
//向上提升 总层级+1
level++;
//新建一层 首先是连接最新加入的头尾节点
Node newHead = new Node(Node.headKey, null);
Node newTail = new Node(Node.tailKey, null);
//水平连接
newHead.right = newTail;
newTail.left = newHead;
//上下连接
insertUp2down(newHead, head);
insertUp2down(newTail, tail);
//全局变量head,tail表示的是最高层头尾节点,所以此时需要提升原头尾节点到最高层
head = newHead;
tail = newTail;
/*---------------------在需要提升总层级的情况下,至此跳表的总层数上升了一层, 接下来提升元素---------------------------*/
}
//如果插入元素的前一个元素上面是null 则往左偏移找到上层
while (null == p.up) {
p = p.left;
}
p = p.up;
//新建node并连接
Node e = new Node(key, null);
insertpre2aft(p, e);
insertUp2down(e, newNode);
newNode = e;
currentLevel++;
}
size++;
}
/**
* 插入时查找插入位置的前一个位置
*/
private Node find(Integer key) {
Node p = head;
//确保从上到下每级向右查找
while (true) {
//当前级向右查找,直到找到表里的key大于或等于传入的key
while (p.right.key != tail.key && p.right.key <= key) {
p = p.right;
}
//跳出循环开始下跳一级 先判断是否有下一级
if (null != p.down) {
p = p.down;
} else {
return p;
}
}
}
/**
* p后水平插入q
*
* @param p
* @param q
*/
private void insertpre2aft(Node p, Node q) {
Node qnext = null;
qnext = p.right;
p.right = q;
q.left = p;
qnext.left = q;
q.right = qnext;
}
private void insertUp2down(Node up, Node down) {
up.down = down;
down.up = up;
}
/**
* 打印
*/
public void print() {
Node tempHead = head;
Node tempTail = tail;
Node p = tempHead;
StringBuilder sb = new StringBuilder();
while (true) {
while (p.right != tempTail) {
p = p.right;
sb = sb.append(p.key).append(" ");
}
p = tempHead;
if (null == p.down) {
System.out.println(sb);
return;
}
tempHead = tempHead.down;
tempTail = tempTail.down;
p = p.down;
System.out.println(sb);
sb.delete(0,sb.length());
}
}
public static void main(String[] args) {
SkipList skipList = new SkipList();
for (int i = 1; i <= 1000; i++) {
skipList.put(i, null);
}
skipList.print();
}
}