带你轻松搞懂跳表(skip list)


什么是跳表

我们知道二叉搜索算法能够高效的查询数据,但是需要一块连续的内存,而且增删改效率很低。

跳表,是基于链表实现的一种类似“二分”的算法。它可以快速的实现 增,删,改,查 操作。

链表,相信大家都不陌生,维护一个有序的链表是一件非常简单的事情,我们都知道,在一个有序的链表里面,查询跟插入的算法复杂度都是O(n)。

在这里插入图片描述

我们能不能进行优化呢,比如我们一次比较两个呢?那样不就可以把时间缩小一半?

在这里插入图片描述

同理,如果我们4个4个比,那不就更快了?

在这里插入图片描述

就好像火车,有快车有慢车;快车停得站少,慢车停得多。所以,从一个地方到另一个地方,我们需要先乘坐快车,之后换乘慢车。

跳表就是这样的一种数据结构(利用空间换时间的方式,提高查询效率 ),结点是跳过一部分的,从而加快了查询的速度。

跳表跟红黑树和AVL树又有什么差别呢?

既然 两者的算法复杂度差不多 ,为什么Redis要使用跳表而不使用红黑树呢?跳表相对于红黑树,主要有这几个优点:

  1. 代码相对简单,手写个跳表还有可能,手写个红黑树试试?
  2. 如果我们要查询一个区间里面的值,用平衡树可能会麻烦。这里的麻烦指的是实现和理解上,平衡二叉树查询一段区间也是可以做到的。
  3. 删除一段区间,这个如果是平衡二叉树,就会相当困难,毕竟设计到树的平衡问题,而跳表则没有这种烦恼。
  • 空间复杂度 O(n):

对于每层的期待:第一层n,第二层n/2,第三层n/22 ,…,直到 n/2logn=1。所以,总空间需求:

S = n + n/2 + n/22 + … + n/2log n < n(1 + 1/2 + 1/22 + … + 1/2) =2n

然而原始链表包含 n 个元素,索引节点的总和是 n,因此他的空间复杂度为 O(n)

  • Skip List高度:

对每层来说,它会向上增长的概率为1/2,则第m层向上增长的概率为1/2m;n个元素,则在m层元素数目的期待为Em = n/2m;当Em = 1,m = log2n即为层数的期待。故其高度期待为 Eh = O(log n)。

跳表的性质:
  • 每条链必须包含两个特殊元素:+∞ 和 -∞
  • S0包含所有的元素,并且所有链中的元素按照升序排列。
  • 每条链中的元素集合必须包含于序数较小的链的元素集合

在这里插入图片描述

查询

假如我们要查询11,那么我们从最上层出发,发现下一个是5,再下一个是13,已经大于11,所以进入下一层,下一层的一个是9,查找下一个,下一个又是13,再次进入下一层。最终找到11。

在这里插入图片描述

是不是非常的简单?我们可以把查找的过程总结为一条二元表达式(下一个是否大于结果?下一个:下一层)。理解跳表的查询过程非常重要,试试看查询其他数字,只要你理解了查询,后面两种都非常简单。

/* 如果存在 x, 返回 x 所在的节点, 
   否则返回 x 的后继节点 */  

find(x) {  
    p = top;  
    while (1) {  
        while (p->next->key < x) {
            p = p->next;  
		}
		if(p->next->key == x){
			return p->next;
		}
        else if (p->down == NULL) {
            return p->next;  
		}
		else 
        	p = p->down;  
    }
}  

插入

插入数据看起来也很简单,跳表的原始链表需要保持有序,所以我们会向查找元素一样,找到元素应该插入的位置。如下图所示,要插入数据6,整个过程类似于查找6,整个的查找路径为 1、1、1、4、4、5。查找到第底层原始链表的元素 5 时,发现 5 小于 6 但是后继节点 7 大于 6,所以应该把 6 插入到 5 之后 7 之前。整个时间复杂度为查找元素的时间复杂度 O(logn)。

在这里插入图片描述

如下图所示,假如一直往原始列表中添加数据,但是不更新索引,就可能出现两个索引节点之间数据非常多的情况,极端情况,跳表退化为单链表,从而使得查找效率从 O(logn) 退化为 O(n)。那这种问题该怎么解决呢?我们需要在插入数据的时候,索引节点也需要相应的增加、或者重建索引,来避免查找效率的退化。那我们该如何去维护这个索引呢?

在这里插入图片描述

首先要从最底层开始,插入被插入的元素。然后看看从下而上,是否需要逐层插入。可是到底要不要插入上一层呢?我们都知道,我们想每层的跳跃都非常高效,越是平衡就越好(第一层1级跳,第二层2级跳,第3层4级跳,第4层8级跳)。但是用算法实现起来,确实非常地复杂的,并且要严格地按照2地指数次幂,我们还要对原有地结构进行调整。所以跳表的思路是抛硬币,听天由命,产生一个随机数,50%概率再向上扩展,否则就结束。这样子,每一个元素能够有X层的概率为0.5^(X-1)次方。

删除

同插入一样,删除也是先查找,查找到了之后,再从下往上逐个删除。比较简单,就不再赘叙。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值