Java 实现 跳表skiplist


完整代码地址github
关于跳表的定义与用途,已经有很多不错的资料了,此篇文章主要是分享记录下Java实现

定义节点

@Data
    private static class SkipListNode {
        private int value = -1;
        // 节点的前一个节点
        private SkipListNode backward;
        // 节点的下一个节点数组
        private SkipListNode[] next;

        public SkipListNode() {
        }

        public SkipListNode(int value, int level) {
            this.value = value;
            this.next = new SkipListNode[level];
        }

        @Override
        public String toString() {
            return "SkipListNode{" +
                    "value=" + value +
                    '}';
        }
    }

类变量

 // 最大层数
    private final static int MAX_LEVEL = 32;
    // 层数概率因子
    private final static double P = 0.25;
    // 头节点
    private SkipListNode header;
    // 尾节点
    private SkipListNode tail;
    // 当前最大层级
    private int level = 1;
    // 节点数量
    private int length;
    
	public SkipList() {
        this.header = new SkipListNode();
        this.header.setNext(new SkipListNode[32]);
    }

插入实现

/**
     * 跳表插入函数
     * @param value
     */
    public void insert(int value) {
        int level = randomLevel();
        SkipListNode skipListNode = new SkipListNode(value, level);
        SkipListNode curNode = this.header;

        int curLevel = level - 1;
        // 从当前所有节点中的最高层数开始遍历
        while (curLevel >= 0) {
            // 依次对没一层进行搜寻并连接节点
            while (curNode.next[curLevel] != null && curNode.next[curLevel].value < value) {
                curNode = curNode.next[curLevel];
            }
            if (curNode.next[curLevel] != null) {
                // 说明 curNode.next[curLevel].value >= value,则将节点插入curNode 和 curNode.next[curLevel] 之间
                // 否则该层没有找到节点间插入位置,直接插入该层最尾处
                skipListNode.next[curLevel] = curNode.next[curLevel];
            }
            curNode.next[curLevel] = skipListNode;
            // 进入下一层
            curLevel--;
        }
        // 此时以及是最底层了,backward 直接指向curNode,为上一个节点
        skipListNode.backward = curNode;
        length++;
        this.level = Math.max(this.level, level);
        // 末尾节点变更
        if (skipListNode.next[0] == null) tail = skipListNode;

    }

查找

    /**
     * 跳表查找函数
     * @param value
     * @return
     */
    public SkipListNode find(int value) {

        int curLevel = this.level - 1;
        SkipListNode curNode = this.header;

        while (curLevel >= 0) {
            // 在curLevel层搜索,
            while (curNode.next[curLevel] != null && curNode.next[curLevel].value < value) {
                curNode = curNode.next[curLevel];
            }
            // 如果当前找到,则会直接一直下沉,没有找到,则会下一层继续向右寻找
            curLevel--;
        }
        // 最后判断下一个节点是否为寻找的值
        if (curNode.next[0] != null && curNode.next[0].value == value) {
            return curNode.next[0];
        } else {
            return null;
        }
    }

删除实现

    /**
     * 跳表删除函数
     * @param value
     * @return
     */
    public SkipListNode delete(int value) {

        // 先尝试找节点,找不到直接返回
        SkipListNode skipListNode = find(value);
        if (skipListNode == null) return null;
        int curLevel = this.level - 1;
        SkipListNode curNode = this.header;
        // 根据前面找到的节点,再来一次遍历,只要找到下一个节点是需要删除的节点,则直接将当前节点指向被删除节点的下一个节点
        while (curLevel >= 0) {
            while (curNode.next[curLevel] != null && curNode.next[curLevel] != skipListNode) {
                curNode = curNode.next[curLevel];
            }
            if (curNode.next[curLevel] != null) {
                curNode.next[curLevel] = curNode.next[curLevel].next[curLevel];
            }
            curLevel--;
        }
        // 尾节点判断
        if (skipListNode.next[0] == null) {
            tail = skipListNode.backward;
        }
        skipListNode.backward = null;
        this.length = this.length - 1;
        return skipListNode;
    }

辅助函数

/**
     * 按一定的概率生成节点层数,P为统计所得,和redis一样
     *
     * @return
     */
    private int randomLevel() {
        int level = 1;
        while (Math.random() < P && level < MAX_LEVEL) {
            level += 1;
        }
        return level;
    }

    // 显示跳表中的结点
    public void display() {
        SkipListNode p = header;
        while (p.next[0] != null) {
            System.out.println(p.next[0] + " ");
            p = p.next[0];
        }
        System.out.println();
    }

测试代码与结果

SkipList skipList = new SkipList();
        skipList.insert(3);
        skipList.insert(4);
        skipList.insert(1);
        skipList.display();
        System.out.println();
        System.out.println(skipList.find(3));
        System.out.println(skipList.find(5));
        System.out.println();
        skipList.insert(5);
        skipList.display();
        System.out.println();
        skipList.delete(4);
        skipList.display();

output:
SkipListNode{value=1} 
SkipListNode{value=3} 
SkipListNode{value=4} 


SkipListNode{value=3}
null

SkipListNode{value=1} 
SkipListNode{value=3} 
SkipListNode{value=4} 
SkipListNode{value=5} 


SkipListNode{value=1} 
SkipListNode{value=3} 
SkipListNode{value=5}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值