图文详解Redis跳跃表skiplist

列表

说到列表,我们一般会想到它的2种实现方式:数组和链表。下面对比一下2种方式的优缺点:

底层实现 特点 优点 缺点
数组 内存地址空间连续 1. 支持O(1)复杂度通过偏移量随机访问元素 1.插入删除操作的平均时间复杂度为O(n);
2.存在未使用的数组空间,一定程度上浪费了内存空间;
3.数组需要动态扩容缩容和新旧数组复制,影响性能
链表 内存地址不连续,每个链表节点都会记录下一个节点的内存地址 1. 插入删除操作平均时间复杂度为O(1);
2. 链表多长就占多少个空间,没有浪费多余内存
元素查询时间复杂度为O(n),n为链表长度;

接下来我以Java的List举例说明2种实现方式。


数组实现(ArrayList)

​ List实现类ArrayList的底层实现是数组,现假设有整型列表List<Integer> arrList = new ArrayList<>();,其底层数组如图:

在这里插入图片描述

ArrayList默认的容量大小是10,当我们往列表添加7个元素后,效果如图所示,如果要获取第4个元素22,我们只需进行arrList.get(3)就行,时间复杂度O(1)。但当我们要删除第4个元素时,要把它后面所有值一次往前挪一位,平均时间复杂度为O(n),同样的插入时后面所有元素一次往后挪一位。


链表实现(LinkedList)

​ List实现类LinkedList的底层实现是链表,由一个或多个链表节点Node连接而成,是一个双端链表,底层实现结构如下图:
在这里插入图片描述

​ 同样的,当我们要访问第4个元素时,它需要从头开始遍历,路径为41->2->16->22,才能得到指定位置的元素,平均时间复杂度为O(n)。如果要删除第4个元素,在删除的那瞬间,只需要把被删除元素前驱节点的next和后继结点的prev改变即可,没有元素的移动,只需要O(1)复杂度,但要注意的是:仅仅是删除的瞬间为O(1),删除前我们要先找到这个元素,查找时间复杂度仍为O(n),插入操作同理。


关于有序列表的思考

​ 有序列表指的是列表里面的元素值是有序的,要么升序要么降序,按某种指定的规则来排序。对于有序的数组,我们可以用二分法花费O(logn)复杂度查找到指定元素所在的下标,但从数组的结构来看,如果要在数组中删除指定元素或在指定元素的前/后插入新元素,时间复杂度O(n);对于有序的链表,查询元素位置复杂度依旧是O(n),插入和删除也是O(1)没变。

​ 一句话概括就是:有序数组查询快、增删慢,有序链表查询慢、增删快。

​ 假设我们现在想要实现一个即能快速查询、又能做到快速增删的数据结构,我们该如何取舍呢?答案就是:“小孩子才做选择题,我全都要!~”,我们今天的合体版主角应运而生——跳跃表。(忽略前摇过长- -!)


什么是跳跃表?

跳跃表

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值