Leetcode 1206 设计跳表

130 阅读1分钟

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;

    }
}