import java.util.Random;
/**
* @author zzyuan
* @date 2021/11/6 - 20:17
*
*/
public class SkipList<E extends Comparable<E>> {
//表示跳表的高度,包括原始链表这一层
private static final int MAX_LEVEL = 16;//跳表的高度是16
//内部类Node
private class Node<E extends Comparable<E>>{
E data;//结点数据
/*
表示当前节点在所有层的下一个节点的指针, 从上层切换到下层,就是数组下标减去 1
nextNodes[0] 表示当前节点在第一层的下一个节点
nextNodes[1] 表示当前节点在第二层的下一个节点
nextNodes[2] 表示当前节点在第三层的下一个节点
nextNodes[3] 表示当前节点在第四层的下一个节点
...
nextNodes[15] 表示当前节点在第十六层的下一个节点
*/
Node[] nextNodes;
//记录当前节点维护的索引节点的最大高度
int maxIndexLevel = 0;
Node(E data) {
this.data = data;
nextNodes = new Node[MAX_LEVEL];//跳表的高度是16
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("{ data: ");
builder.append(data);
builder.append("; levels: ");
builder.append(maxIndexLevel);
builder.append(" }");
return builder.toString();
}
}
// 表示当前跳表最大的高度 (包含了原始链表层,所以默认初始值是 1)
private int levelCount;
// 虚拟头结点
private Node dummyHead;
private Random random = new Random();
//跳表初始化
public SkipList() {
this.levelCount = 1;
this.dummyHead = new Node(-1);
}
public boolean contains(E e){
return get(e) != null;
}
//查询操作
//log(n)
public Node get(E e){
Node curr = dummyHead;
//从最高一层 往下 一层一层 的寻找元素所在的区间
for(int i = levelCount - 1 ; i >= 0 ; i--){
//同层比较(i 层)
//只要下一个结点值 比 待查找的元素小,一直往右前进
while(curr.nextNodes[i] != null
&& curr.nextNodes[i].data.compareTo(e) < 0){
curr = curr.nextNodes[i];
}
}
//到最底层了:比较e结点 和 下一个结点大小关系
if(curr.nextNodes[0] != null
&& curr.nextNodes[0].data.compareTo(e) == 0){
return curr.nextNodes[0];
}
//没找到结点
return null;
}
//插入操作
public void add(E e){
//维护一层索引
int level = dummyHead.nextNodes[0] == null ? 1 : randomLevel();
Node[] prevNodes = new Node[level];
for(int i = 0 ; i < level ; i++){
prevNodes[i] = dummyHead;
}
//1.找到要插入节点的前面一个节点
Node prev = dummyHead;
for(int i = levelCount - 1 ; i >= 0 ; i--){
while(prev.nextNodes[i] != null && prev.nextNodes[i].data.compareTo(e) < 0){
prev = prev.nextNodes[i];
}
if(i < level)
prevNodes[i] = prev;
}
Node newNode = new Node(e);
//2.将节点插入到节点prev的后面
for(int i = 0 ; i < level ; i++){
newNode.nextNodes[i] = prevNodes[i].nextNodes[i];
prevNodes[i].nextNodes[i] = newNode;
}
//维护最大高度
if(levelCount < level){
levelCount = level;
}
}
//随机给出维护高度
private int randomLevel() {
int level = 1;
for (int i = 1; i < MAX_LEVEL; i++) {
if (random.nextInt() % 2 == 1) {
level++;
}
}
return level;
}
public void remove(E e) {
// 1. 找到需要删除节点的前一个节点,以及删除节点对应的索引节点的前一个索引节点
Node<E>[] prevNodes = new Node[levelCount];
Node prev = dummyHead;
for (int i = levelCount - 1; i >= 0; i--) {
while (prev.nextNodes[i] != null
&& prev.nextNodes[i].data.compareTo(e) < 0) {
prev = prev.nextNodes[i];
}
prevNodes[i] = prev;
}
// 2. 对每一层进行删除节点
// 先判断节点是否存在,存在的话才执行删除
if (prev.nextNodes[0] != null
&& prev.nextNodes[0].data.compareTo(e) == 0) {
// 对每一层进行删除节点
for (int i = levelCount - 1; i > 0; i--) {
Node delNode = prevNodes[i].nextNodes[i];
if (delNode != null && delNode.data.compareTo(e) == 0) {
prevNodes[i].nextNodes[i] = delNode.nextNodes[i];
delNode.nextNodes[i] = null;
}
}
}
}
}