4.1跳表

零 跳表介绍

  跳表在实践中用得较少。我所知的两处应用,一个是redis中zset的实现,一个是java的ConcurrentSkipListMap与ConcurrentSkipListSet。跳表的发明者是William Pugh于1990年发明于论文Skip Lists: A Probabilistic Alternative to Balanced Trees
  跳表底层是一个链表。这个链表是按大小顺序排列的。
  然后在底层数据链表上建N层索引,如图所示:
在这里插入图片描述
  每层索引都有个起始节点,叫做头。各层的头都是对齐的,都指向第一个节点。
  对于底层链表节点来说,除了value以外,只有一个属性next。
  而上层的索引有三个属性value,next和down。

一 跳表的添加

  跳表的添加,第一步是快速找到插入点,然后将数据插入进去。
  这个因为有前几级索引,都很简单。
  而什么时候建上一级索引呢?
  跳表的逻辑竟然是随机数。以JDK自带的跳表为例子,其代码是这样的:

int rnd = ThreadLocalRandom.nextSecondarySeed();
if ((rnd & 0x80000001) == 0) {/*省略内部建索引代码*/}

  对于跳表来说,利息的是隔一个位置建一个索引。但是如果严格这样来的话,代码会非常复杂。所以为了简化逻辑,都用随机数。
  随机生成上层索引的代码。

// 生成上层
while (random.nextBoolean()) {
    // 随机决定是否生成索引
    final Node<T> index = new Node<>();
    index.value = t;
    index.down = node;
    index.level = node.level + 1;
    if (head.level < index.level) {
        head = newHead(index);
    } else {
        final Node<T> tNode = findNode(t, node.level + 1);
        tNode.append(index);
    }
    node = index;
}

  如果不用随机数改成布尔值变量,一正一反会有问题的。因为用while循环去建立上级索引,所以不会出现连续两 e m s p ; emsp; emsp;emsp;个true,也就是说索引永远只有一级。

二 跳表的删除

  跳表的删除,也是找。
  如果找到了索引,那么一直往下删除就行了。
  例如,以下跳表删除2:
在这里插入图片描述
在这里插入图片描述
  如果没有找到索引,那么删最底层的链表就行了。
  如果删除头,不需要创建新的头索引,只需要将索引重新指向第二个元素的索引就行。上图中就是将上两行的0改成1,再将第二行的0指向第三行的1.就完成了头部的删除。
  删除头部的结果如下:
在这里插入图片描述
  所以就是删除头的逻辑比较复杂一点。
  删除头部代码如下:

if (node == head) {
    // 每层都找下一个
    LinkedList<Node<T>> list = new LinkedList<>();
    forEachHeads(list::add);
    // 最底层的第二个
    final Node<T> next = list.getLast().next;
    final Node<T> newHead = list.stream().filter(x -> x.next != null && x.next.value.compareTo(next.value) == 0)
            .findFirst().get();
    // 在新的头上建头
    // 上一层指向它
    // 从上一层开始把指改了。
    forEachHeads(x->x.value = newHead.next.value);
    // 上一层的指向新的head
    final Node<T> tNode = list.stream().filter(x -> x.level == newHead.level + 1).findFirst().get();
    tNode.down = newHead.next;
    return;
}

源码仓库

  Git地址:https://e.coding.net/buildt/learn/skiplist.git

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒过来摸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值