(7)Redis有序集合跳表实现原理

  数据结构&算法模块总结

1.跳表与链表


    ①原始链表查找效率为O(N)
    跳表优化思路:  每隔两个或两个以上节点时,提取一个节点到上一级,抽取出来的一级称为索引或索引层。down指针,可以指向下一级结点 。 这种链表加多级索引的结构,就是跳表。
    例如要查找节点16,可以现在索引层遍历,当遍历到13发现下一个节点为17。此时不能再继续走,所以从13节点往下走,然后再遍历到16节点
     ③索引层高度与效率:如果在第一级索引上创建第二级。那么查找16过程为1->7->7->9->13->13->16,共6节点,效率有提升。

2.跳表查询效率计算


(1)第k层节点个数    

    如果每两个节点抽取一个节点作为上一级索引的节点,那第一级索引的结点个数大约就是n/2,第二级索引的结点个数大约就是n/4,第三级索引的结点个数大约就是n/8,依次类推,也就是说, 第k级索引的结点个数是第k-1级索引的结点个数的1/2 ,那第k级索引结点的个数就是n/(2 k )。

(2)查询复杂度

     假设索引有h级,最高级的索引只有2个结点。通过上面的公式,可以得到n/(2h)=2,从而求得h=log2n-1。如果包含原始链表这一层,整个跳表的高度就是log2n。在跳表中查询某个数据的时候, 如果每一层都要遍历m个结点,那在跳表中查询一个数据的时间复杂度就是 O(m*logn)(横向遍历节点个数*纵向总高度) ,因此复杂度就是O(logn)
 每一级索引都最多只需要遍历3个结点,也就是说m=3。即m=跨节点个数(2)+1
    假设我们要查找的数据是x,在第k级索引中,我们遍历到y结点之后,发现x大于y,小于后面的结点z,所以我们通过y的down指针,从第k级索引下降到第k-1级索引。 在第k-1级索引中,y和z之间只有3个结点(包含y和z),所以,我们在K-1级索引中最多只需要遍历3个结点, 依次类推,每一级索引都最多只需要遍历3个结点 (但如果有插入操作打乱节点规律,则不一定为3节点)

3.跳表空间复杂度计算


(1)每次节点个数:

    假设原始链表大小为n,那第一级索引大约有n/2个结点,第二级索引大约有n/4个结点,以此类推,每上升一级就减少一半,直到剩下2个结点。

(2)索引节点总和

    上述第1到第k层索引的结点总和=n/2+n/4+n/8…+8+4+2=n-2,因此复杂度为0(N)

(3)复杂度缩减方法——提高节点跨度

    以3跨度为例,总的索引结点大约就是n/3+n/9+n/27+…+9+3+1=n/2,因此索引跨度越大会减少空间复杂度。

4.跳表插入和删除


(1)插入操作

    为了保证链表有序性,先找到插入位置然后插入,因此时间复杂度就是查找复杂度O(log N)。
    例如插入6, 先找到6的位置(5和7中间),然后直接插入 (假设链表是双链表)

(2)删除操作(同上)

5.跳表索引动态更新


(1)更新原因    

    我们不停地往跳表中插入数据时,如果不更新索引,就有可能出现某2个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。

(2)更新方法

    不同于红黑树通过旋转左右子树平衡,跳表利用随机函数维护平衡性。通过一个随机函数,来决定将这个结点插入到哪几级索引中,比如随机函数生成了值K,那我们就将这个结点添加到第一级到第K级这K级索引中

     从概率上来讲,能够保证跳表的索引大小和数据大小平衡性,不至于性能过度退化。具体随机实现无规范。

6.跳表与红黑树


    由于Redis在有序集合中才会用到,主要涉及到的操作如下:

  • 插入一个数据;

  • 删除一个数据;

  • 查找一个数据;

  • 按照区间查找数据(比如查找值在[100, 356]之间的数据);

  • 迭代输出有序序列。

    与红黑树主要差别在于区间查找数据,由于两者查找一个数的时间复杂度都是logn,但是跳表只需要在原始链表层往后遍历即可,而红黑树还要进行回溯操作才能遍历,复杂度高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值