数据结构与算法之美-11 |跳表

一、什么是跳表

二分查找底层依赖的是数组随机访问的特性,所以只能用数组来实现。如果数据存储在链表中,还想使用二分查找,只需要对链表稍加改造,就可以支持类似“二分”的查找算法。我们把改造之后的数据结构叫做跳表(Skip list)。

二、如何理解跳表

对于一个单链表来讲,即便链表中存储的数据是有序的,如果要想在其中查找某个数据,也只能从头到尾遍历链表。这样查找效率就会很低,时间复杂度会很高,是 O(n)。
那怎么来提高查找效率呢?如果像图中那样,对链表建立一级“索引”,查找起来是不是就会更快一些呢?每两个结点提取一个结点到上一级,我们把抽出来的那一级叫做索引或索引层。
在这里插入图片描述
这样如果我们想去寻找某个数据,比如10,可以先在索引层遍历,找到对应范围9-13之后,再下降到原属链表这一层,进行遍历即可找到。
加来一层索引之后,查找一个结点需要遍历的结点个数减少了,也就是说查找效率提高了。如果数据量比较大的情况下,可以使用多级索引,在构建索引之后,查找效率的提升就会非常明显。
在这里插入图片描述
这种链表加多级索引的结构,就是跳表。
跳表采用的是二分思想,查询速度会非常快,时间复杂度和二分算法相同都是O(logN)。

三、跳表是不是很浪费内存?

在实际的软件开发中,原始链表中存储的有可能是很大的对象,而索引结点只需要存储关键值和几个指针,并不需要存储对象,所以当对象比索引结点大很多时,那索引占用的额外空间就可以忽略了。

四、高效的动态插入和删除

因为跳表的原始数据结构是链表,因此不存在插入后数据位移的问题,所以插入的关键还是查找到对应插入的位置。
对于纯粹的单链表,需要遍历每个结点,来找到插入的位置。但是对于跳表来说,查找某个结点的时间复杂度是 O(logn),所以这里查找某个数据应该插入的位置,方法是类似的,时间复杂度也是 O(logn)。
在这里插入图片描述
删除和插入类似。

五、跳表索引动态更新

当不停地往跳表中插入数据时,如果不更新索引,就有可能出现某 2 个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。
在这里插入图片描述
跳表的索引是一种动态的数据结构,为了避免复杂度退化及查找、插入、删除操作性能下降,需要进行索引的平衡和维护,跳表是通过随机函数来维护平衡性,这个随机函数怎么实现,之后找到参考资料我补充。

猜你喜欢

转载自blog.csdn.net/qq_38173650/article/details/114010382