数据结构与算法:跳表的实现

我们知道Redis、LevelDB 都是著名的 Key-Value 数据库,Redis中 的 SortedSet以及LevelDB 中的 MemTable 都用到了跳表,那么什么是跳表呢?跳表又是如何实现的呢?

1、有序链表

说跳表之前,先说说有序链表:
在这里插入图片描述
一个有序链表搜索、添加、删除的平均时间复杂度是都是O(n)。有序数组的随机访问时间复杂度为O(1),在查询某个特定的元素的时候能够进行二分搜索优化,时间复杂度为O(logn)。因此有序链表的访问效率低于有序数据。那么就需要有某种方法来让有序链表搜索、添加、删除的平均时间复杂度降低至 O(logn),跳表这种方法就出现了。

2、什么是跳表

跳表,又叫做跳跃表、跳跃列表,是在有序链表的基础上增加了“跳跃”的功能,它是由William Pugh于1990年发布的,设计的初衷是为了取代平衡树(比如红黑树)。

跳表的结构如下:
在这里插入图片描述
从图中可以看到, 跳跃表主要由以下部分构成:

  • 表头(first):负责维护跳跃表的节点指针。
  • 跳跃表节点:保存着元素值,以及多个层。
  • 层:保存着指向其他元素的指针。高层的指针越过的元素数量大于等于低层的指针,为了提高查找的效率,程序总是从高层先开始访问,然后随着元素值范围的缩小,慢慢降低层次。
  • 表尾:全部由 NULL 组成,表示跳跃表的末尾。

对比于平衡树,跳表有以下优点:

  • 跳表的实现和维护更加简单。

  • 跳表的搜索、添加、删除的平均时间复杂度为 O(logn)。

  • 跳表在新增、删除节点时不需要复杂的旋转。

3、跳表的搜索

① 从收割head节点的有效层数的最高层开始,从左往右搜索,直至找到一个大于或等于目标的元素,或者到达当前层链表的尾部。

② 如果该元素等于目标元素,则表明该元素已被找到。

③ 如果该元素大于目标元素或已到达链表的尾部,则退回到当前层的前一个元素,然后转入下一层进行搜索。
在这里插入图片描述
比如要查找17这个数,先从头结点的顶层开始找,找到21,大于17,则返回头结点转入下一层,找到9,小于17,则从9向右查找到21,大于17,则返回上一节点9,转入下一层,开始搜索,发现9的下一个是17,说明被找到。

4、跳表的添加

① 根据跳表搜索的方式确定节点添加的位置

  • a:如果已经存在这个节点,则覆盖
  • b: 如果不存在,则应该找到第一个大于这个需要新添加的节点的位置

② 随机决定新添加元素的层数

例如,我们需要添加15这个元素:
在这里插入图片描述

5、跳表的删除

① 根据跳表搜索的方式确定节点删除的位置,如果已经存在这个节点,则删除

② 删除一个元素后,这个元素的所有前驱节点指向这个节点的所有后继节点

③ 删除一个元素后,整个跳表的层数可能会降低

例如,我们需要添加9这个元素:
在这里插入图片描述

6、代码实现

public class SkipList<K, V> {
   
    //链表长度
    private int size;
    //虚拟节点 null
    private Node<K, V> first;
    //默认为32层
    private static final int MAX_LEVEL = 32;
    //redis中的层数因子
    private static final double P = 0.25;
    //有效层数
    private int level;

    private Comparator<K> comparator;

    public SkipList() {
   
        this(null);
    }

    public SkipList(Comparator<K> comparator) {
   
        this.comparator = comparator;
        first = new Node<K, V>(null, null, MAX_LEVEL);
    }

    public int size() {
   
        return size;
    }

    //返回旧的值
    public V put(K k, V v) {
   
        checkKey(k);
        Node<K, V> node = this.first;
        //放置前驱节点
        Node<K,V>[] pres=new Node[level];
        int comp = -1
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值