跳表

定义

链表加多级索引的结构,称为跳表。

特点

单链表是有序的,然后提升多层索引,提高查询效率。

基于链表实现的二分查找。

每两个节点会抽出一个节点作为上一级索引的节点,第k级索引的个数,是第k-1级索引个数的1/2,那么第k级索引的个数就是n/2^k。

每两个节点会抽出一个节点作为上一级索引的节点,查询的时间复杂度为logn

是基于链表实现的二分查找,主要利用了空间换时间的思路。

因为每2个节点抽取一个节点提升为索引,所以每个节点最多访问3个元素。

空间复杂度

  1. 假设有n个节点的有序链表,每两个节点提取一个为索引,第一级索引为n/2,第二级为n/4,以此类推,每提升一级的个数,就是上一级索引的二分之一倍,相加起来为n/2+n/4+n/8+...+n/2^k+...+8+4+2=n-2,所以空间复杂度为O(n)。也就是说,将n个节点构成成为跳表,需要额外近似n个节点大小的空间存储索引。
  2. 降低空间复杂度的办法为,可以更多个节点抽取一个节点作为索引,如每3个节点,或者每5个节点抽取一个节点上升为索引,这样索引节点数减少,空间复杂度降低。如每3个节点抽取一个节点作为索引,那么索引个数为n/3+n/9+n/18+...+n/3^2+...+18+9+3=n/2,虽然空间复杂度为O(n),但索引节点总个数为n/2,降低为原链表的一半,所以需要的额外空间更少了。
  3. 实际开发过程中,原始链表节点存储的可能是很大的对象,而索引存储的关键值或几个指针,所以索引节点的大小比原始链表小的多,所以索引节点大小和占用的内存我们都可以忽略不计。

跳表操作

高效的插入和删除

  1. 插入:单向链表的插入本身时间复杂度就是O(1),所以通过跳表索引,以O(logn)的时间复杂度定位到要插入的节点,然后插入数据,非常高效。
  2. 删除:利用跳表O(logn)定位到要删除的节点,因
  3. 为删除必须要定位到前驱节点,所以比插入要多遍历一次区间节点。当然如果我们要是用双向链表,就不用考虑寻找前驱节点的问题了。

索引的更新

当频繁的插入数据,区间节点内节点数量增大,当插入不均匀时,可能导致一个区间内节点特别多,这样导致此节点退化成单向链表,复杂度增大,所以我们要及时的更新索引,避免复杂度退化。

更新索引的策略有使用随机函数,提升增加的节点,升级为索引。随机函数选择很有讲究,从概率上讲,要能够保证跳表索引大小和数据平衡,减少复杂度退化。

应用

redis的有序集合就是跳表实现。

  • 为什么选择跳表而非红黑树,通过redis使用手册查看有序集合的操作有:
  1. 插入一个数据。
  2. 删除一个数据。
  3. 查找一个数据。
  4. 按区间查找数据。
  5. 迭代输出有序序列。

其中,插入,删除,查找,迭代输出这几个操作,红黑树也可以实现,且复杂度跟跳表一样都是O(logn),但是按区间查找,跳表比较优越,跳表在根据索引找到区间里对应的起始点后,顺序往后输出就可以,这样非常高效,而红黑树不行。

  • 跳表的代码的可读性比较好,比红黑树容易。
  • 跳表可以通过改变构建索引策略,来有效平衡执行效率和内存消耗,这点很灵活。

代码实现

todo

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值