java 实现redis跳表

跳表的相关原理参见
redis跳跃表图解&插入详述


import java.util.Random;

/**
 
 * @creat 2021-09-18-2021/9/18
 *
 *  定义跳表相关信息
*/


public class SkipList<T extends Comparable>{

    /**
     * 跳表的节点定义
     *  SkipListLevel类中存储每个层次上的信息
    */
    static class SkipListNode<T> {
        //后置节点;
        public SkipListNode backward;

        //结点中保存的值;
        T val;

        //层次信息;
        SkipListLevel[] levels;

        public SkipListNode(T val, int l) {
            this.val = val;
            levels = new SkipListLevel[l];
        }

        public SkipListNode(int l ) {
            levels = new SkipListLevel[l];
        }

        public SkipListNode() {
        }

        static class SkipListLevel {

            //当前层次的前置节点;
            SkipListNode forward;

            //距离下个节点的距离;
            int span;
        }
    }
    //跳表最大层数
    private static final int MAX_LEVEL = 32;

    private static final double P = 0.5;

    //头节点和尾节点;
    private final SkipListNode<T> head;
    private final SkipListNode<T> tail;

    //当前表的长度
    public int length;

    //当前表的层
    public int level;

    public SkipList(){
        head = creatNode(MAX_LEVEL);
        tail = creatNode();
        tail.backward = head;
        for(int i = 0; i < MAX_LEVEL; ++i){
            head.levels[i] = new SkipListNode.SkipListLevel();
            head.levels[i].forward =  tail;
            head.levels[i].span = 1;
        }
        tail.backward = head;
        level = 1;
    }
    public void add(T t){

        //指向当前访问的结点;
        SkipListNode p = this.head;

        //从上至下,每一层需要更新的结点;
        SkipListNode[] update = new SkipListNode[MAX_LEVEL];

        //从上至下,每一层经历过的距离;
        int[] distance = new int[MAX_LEVEL + 1];

        //遍历到该值合适的插入位置
        for(int i = level - 1; i >= 0; --i){
            distance[i] = distance[i+1];
            while(p.levels[i].forward!=tail && t.compareTo(p.levels[i].forward.val) >= 0 ){
                p = p.levels[i].forward;
                distance[i] += p.levels[i].span;
            }
            update[i] = p;
        }

        //将结点随机分配层级;
        int l = RandomLevel();

        //创建结点;
        SkipListNode<T> node = creatNode(t, l);

        //插入Node;
        p.levels[0].forward.backward = node;
        node.backward = p;

        if(l > level){
            //如果分配的l > 当前最高层数,将update,distance信息补上
            for(int i = level; i < l ; ++i){
                update[i] = head;
            }
            level = l; //将level设置为l;
        }
        for(int i = 0; i < l; ++i){

            //修改每一层插入位置的前一个, 和插入结点的forward
            node.levels[i] = new SkipListNode.SkipListLevel();
            node.levels[i].forward = update[i].levels[i].forward;
            update[i].levels[i].forward = node;

            //修改每一层插入位置的前一个, 和插入结点的span
            node.levels[i].span = update[i].levels[i].span  - (distance[0]  - distance[i]);
            update[i].levels[i].span = distance[0] + 1 - distance[i];
        }

        //在 l < level时,更新未涉及到的层次的span
        for(int i = l; i < level; ++i){
            ++update[i].levels[i].span;
        }
        ++this.length;
    }

    /**
     * 为每个待插入的结点随机分配层数
     * 设第n层插入概率为Xn
     * 则第n+1 层的概率为 p*Xn
     * 在本文中设置为 P = 0.5 (注:redis 中设为 0.25)
     * @return int
     */
    private int RandomLevel() {
        Random rand = new Random();
        int l = 1;
        while(rand.nextInt(Integer.MAX_VALUE) < P * Integer.MAX_VALUE){
            l++;
        }
        return Math.min(l, MAX_LEVEL);
    }

    public boolean search(T t){
        SkipListNode p = head;
        for(int i = level - 1; i >= 0; --i){
            while(p.levels[i].forward!=tail && t.compareTo(p.levels[i].forward.val) > 0){
                p = p.levels[i].forward;
            }
        }
        return p.levels[0].forward == tail ? false :p.levels[0].forward.val.equals(t);
    }

    /**
     * 总体逻辑和插入差不多
     * @param t  待删除的元素的值
     * @return Boolean 是否有该元素
     */
    public boolean delete(T t){

        SkipListNode p = head;
        SkipListNode[] update = new SkipListNode[level];

        for(int i = level - 1; i >= 0; --i){
            while(p.levels[i].forward!=tail && t.compareTo(p.levels[i].forward.val) > 0){
                p = p.levels[i].forward;
            }
            update[i] = p;
        }
        if(p.levels[0].forward==tail || !t.equals(p.levels[0].forward.val)) return false; //没有该元素;

        //开始删除
        SkipListNode node = p.levels[0].forward; //待删除的结点;
        node.levels[0].forward.backward = p;
        node.backward = null;


        int l = node.levels.length;//该结点的层次;
        for(int i = 0; i < l; ++i){

            //每一层连接解开;
            update[i].levels[i].forward = node.levels[i].forward;
            node.levels[i].forward = null;

            //更新span信息;
            update[i].levels[i].span = update[i].levels[i].span + node.levels[i].span - 1;

        }
        for(int i = l ; i < level; ++i) --update[i].levels[i].span;

        --this.length;

        //更新level信息。
        for(;level > 1 && head.levels[level-1].forward==tail; --level){}

        return true;
    }

    public T getMax(){
        return (T) tail.backward.val;
    }

    private SkipListNode<T> creatNode() {
        return new SkipListNode<>();
    }
    private SkipListNode<T> creatNode(int len) {
        return new SkipListNode<>(len);
    }
    private SkipListNode<T> creatNode(T t, int l) {
        return new SkipListNode<>(t, l);
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值