SkipList 跳跃表,一种根据 key 高效查找 value 的数据结构,本质是链表。
原生 Java 实现了 ConcurrentSkipListSet 以及 ConcurrentSkipListMap
使用跳跃表的条件:必须包含可以排序的属性,否则没有意义
思路:按照属性大小建立链表,在链表的基础上改造,增加新的引用,分别指向更远处的节点,提高查询效率
如上图所示,假设现在需要查询 22 节点:
- 假设只有一层:依次遍历 head > 3 > 7 > 11 > 19 > 22 ,5次遍历找到
- 假设只有两层:依次遍历 head > 7 > 19 > 26 (发现大于后跳回,走次级引用) -> 22,4次遍历
- 假设存在三层:依次遍历 head > 19(发现为空,走次级引用) > 26(发现大于后跳回,走次级引用) -> 22,3次遍历找到
上图就是跳跃表的核心思路,一般情况下层数越高,查询效率越高,总得来说仍是一种空间换时间的策略,因为需要维护更多的引用。
多层链表的特征:
- 上层链表节点数比下层链表节点数少,
- 第 n 层节点数是底层节点数的的 1 / n
- 每次查询从高层开始,依次向下一层递归
跳跃表只继承特征一和三,因为特征二太难维护:每次增、删、改操作后需要进行大量的操作维护链表结构:
- 添加、删除节点时,该节点往后所有节点可能都要修改
- 修改可以看做删除和添加两个过程,复杂度更高
跳跃表建议每个节点采用随机层数的方式实现,具体过程如下:
这样每次操作时,只需要处理当前节点层数的引用,大大降低复杂度。
跳跃表优化的本质在于跳过无效的节点,提高查询效率。跳过的越多,查询效率越高,总体来说层数过高或者过低对效率都不好:
- 跳跃表层数过高时,占用的内存多,物流损耗严重
- 跳跃表层数过低时,跳跃过的节点少,效率不高
此时就需要从空间和时间两个维度一起考虑,其中上层节点数比下层节点数少可以通过概率学维护,一层概率为1,二层概率为 p ,三级概率为二层的基础上继续 p,以此类推。