SkipList跳表
简介
单向有序链表查找、插入和删除操作时间复杂度为 O(n)
,若在已查找到节点前提下,进行插入和删除时间复杂度为 O(1)
。
对于单向有序链表,如果能够像有序数组一样进行二分查询,那么查询时间复杂度就能控制在 O(logn)
级别。
基于这样的思路,可以创建多条单向有序链表,在理想状态下,每条链表中的节点个数都是上一条链表的一半,假设单向有序链表中有 8 个节点,那么理想情况下可以创建 log8 = 3
条链表。所有 8 个节点出现在第 0 层链 表, 4 个节点出现在第 1 层链表, 2 个节点出现在第 2 层链表。
如此这般就能构造出跳表结构,如下图所示。
在这种理想情况下,查找效率变为 O(logn)
,例如查找节点 4 流程如下:
- 首先访问 level2 层,查找到节点 5 时,大于节点 4 ,需要进入节点 1 的下一层。
- 访问节点 1 的 level1 层,经过节点 3 ,访问节点 5 时,需要进入节点 3 的下一层。
- 访问节点 3 的 level0 层,找到目标节点。
由于链表的构建是动态过程,无法知道某个节点在最优情况下需要处于哪些层,跳表通过随机化的方式来解决这个问题,具体为使第 i 层的节点有概率 p 出现在 i + 1 层。
即最终构建出,第 0 层有 n 个节点,期望第 1 层有 n/p 个节点,第 2 层有 n/(p ^ 2) 个节点,第 k 层有 n/(p ^ k) 个节点,每一个节点在插入时根据随机概率计算其出现的层数。
在 LevelDB
中的 SkipList
还支持多线程访问,对于写操作需要在外部进行加锁,保证只有一个线程写,而对于读操作可以与写操作和多个读操作同时进行。