Leetcode 1206 设计跳表 java实现
redis中zset在数据量多或者不满足使用ziplist的条件下,则会使用skiplist。skiplist的更多原理性分析,这里就不做展开了,通过一定的随机性来满足均摊的性能。
下面是java的跳表实现。每个节点有在区间[1,MAX_LEVEL]中的随机高度。具体方法是randomHeight。新增,删除与查找方法的基本形式都差不多。都是从在最高层开始遍历。为了节省一些遍历次数,在产生随机高度时记录目前最高的高度,因为必然会有一层所以高度的起始值为1。为了简化过程,都是找到临近查找点的前一个节点,因为是链表结构,这样处理的好处是可以方便进行新增与删除操作,否则还需要维护前驱指针。
class Skiplist {
int MAX_LEVEL = 32;
class Node{
int val;
Node[] nexts;
Node(int val, int height){
this.val = val;
this.nexts = new Node[height];
}
}
public int randomHeight(){
int curHeight = 1;
while(curHeight < MAX_LEVEL && Math.random() > 0.75){
curHeight++;
}
if(curHeight > currentLevel){
currentLevel = curHeight;
}
return curHeight;
}
Node head = new Node(-1, MAX_LEVEL);
int currentLevel = 1;
public Skiplist() {
}
public boolean search(int target) {
Node node = head;
for(int l = currentLevel - 1; l >=0 ;l--){
while(node.nexts[l] != null && node.nexts[l].val < target){
node = node.nexts[l];
}
if(node.nexts[l] != null && node.nexts[l].val == target){
return true;
}
}
return false;
}
public void add(int num) {
int height = randomHeight();
Node newNode = new Node(num, height);
Node node = head;
for(int l = currentLevel - 1; l >=0 ;l--){
while(node.nexts[l] != null && node.nexts[l].val < num){
node = node.nexts[l];
}
if(l<=height-1){
Node next = node.nexts[l];
node.nexts[l] = newNode;
newNode.nexts[l] = next;
}
}
}
public boolean erase(int num) {
Node node = head;
boolean flag = false;
for(int l = currentLevel - 1; l >=0 ;l--){
while(node.nexts[l] != null && node.nexts[l].val < num){
node = node.nexts[l];
}
// 这里如果是删除所有 则把if改成while
if(node.nexts[l] != null && node.nexts[l].val == num){
flag = true;
node.nexts[l] = node.nexts[l].nexts[l];
}
}
return flag;
}
}