Java数据结构:跳跃链表

1、跳跃链表

用某种数据结构来维护一组有序的数据的列表,尽可能在插入、删除、查找等操作上能够尽可能的快速。

  • 数组:使用数组存储的话,采用二分法可以在 O(logn) 的时间里找到指定的元素,在进行插入和删除则时间复杂度为 O(n) 
  • 链表:使用链表存储的话,就插入、删除动作而言,所需的时间复杂度为 O(1) ,加上查找所需的时间复杂度为O(n),故插入、删除所需的总的时间复杂度为O(n)。

跳跃链表在有序链表的基础上进行了扩展(它具有二分查找的功能),查找特定值的时间复杂度为O(logn),单插入和删除时间复杂度为O(1),根据时间复杂度加法原则,增删时需要先定位到某位置,所以要加上查询所需O(lngn),所以跳跃链表在查询、插入、删除的时间复杂度为O(lng)。他是一种可以代替平衡树的数据结构。B+树结构的思想和跳跃链表同理。最底层存储数据,将特定数据提取到上一层作为索引。

 

 

小结:跳表的特点:

(1) 由很多层结构组成

(2) 每一层都是一个有序的链表

(3) 最底层的链表包含所有元素

(4) 如果一个元素出现x层,则x下的一层也会出现。

(5) 每个节点包含两个指针,一个指向同一层的下一个元素,一个指向下面一层的元素。

/**
 *跳跃链表
 */
public class SkipListNode {

    //元素
    private int data;
    //同一链表中的下一个元素指针
    private SkipListNode next;
    //指向下面一层的元素指针
    private SkipListNode downNext;
}

PS:包括前面的数据结构,很多时候看一个类的成员变量,便能从宏观上把握这个类的作用。因为无论方法再多,都是再维护这些变量。

2、跳表的增删改查操作

(1)插入节点

插入结点的操作,最底层数据节点会增加,底层往上的各层索引节点会逐渐减少。这时候需要决定插入的节点是否需要添加到各层中作为索引。解决方式:抛硬币法

【抛硬币法】 也就是随机决定新节点是否提拔,每次向上提拔一层的几率是50%

  • 因为跳跃表删除和添加的节点是不可预测的,很难用一种有效的算法来保证跳表的索引部分始终均匀。
  • 随机抛硬币的方法可以让索引部分大体趋于均匀
//抛硬币:
int random_level()  
{  
    K = 1;  
    while (random(0,1))  
        K++;  
    return K;  
} 

(2)删除节点:

  • 只要在【索引层】找到要删除的节点,然后一次查找每一层删除相同节点。
  • 如果某一层索引在删除后只剩下一个节点,那么整个一层就可以干掉了。

(3)查询节点:介绍跳表的图中已说明

 

3、跳表的应用

ConcurrentSkipListMap 

ConcurrentSkipListSet 

Redis sorted set的内部使用HashMap和跳跃表(SkipList)

后续会逐一介绍

4、跳表与其他数据结构的比较

  • 跳跃表 vs 二叉查找树

二叉查找树的插入、删除、查找也是近似 O(logn) 的时间复杂度。 不过,二叉查找树是有可能偏向一方,将退化成O(n)的链表

  • 跳跃表 vs 红黑树

红黑在查找,插入,删除也是近似O(logn)的时间复杂度,通过旋转(改变了原本数据结构)达到近似平衡,比起跳跃表直接通过一个随机数来决定跨越几层要复杂得多

java提供了工业级的红黑树TreeMap,但是链表并没有,需要自己手动实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值