如何提高链表线性查找的效率?
提升维度,空间换时间。
添加第一级索引,视情况逐级添加。
添加多级索引
跳表查询的时间复杂度分析
n/2、n/4、n/8、第k级索引结点的个数就是n/(2^k)
假设索引有h级,最高级的索引有2个结点。n/(2^h)=2,从而求得h=log2(n) - 1
原始链表共有n=20个结点,第k级索引编号k=[log2(20)] - 1 = 4-1=3,由于索引下标从0开始,故k = 0,1,2,3
第3级的索引结点的个数是20/(2^3) = 2.5 向上取整 = 3
第2级的索引结点的个数是20/(2^2) = 5
第1级的索引结点的个数是20/(2^1) = 10
第0级的索引结点的个数是20/(2^0) = 20
与上图的每一层依次对应。
如果要走到第8个结点,它的时间复杂度是log2(8) = 3,所以每一层要遍历3个结点。它的总体时间复杂度是O(logn)
跳表使得最朴素的原始链表时间复杂度从O(n)降到log2(n)的时间复杂度,这是一个很大的改进,Redis也是基于这种原理实现的。如果你要查询第1024个元素,原始链表的做法要遍历1024次才得获得这个元素,而跳表只需要查询log2(1024) = 10次这样一个数量级即可获得该元素的值。
现实中跳表的形态
每一次对跳表的元素增加或删除都要更新整个跳表的索引,维护成本相对较高,在增加或删除的情况下它的时间复杂度也是logn
跳表的空间复杂度分析
跳表查询的空间复杂度分析
原始链表大小为n,每2个结点抽1个,每层索引的结点数:
n/2,n/4,n/8,…,8,4,2
原始链表大小为n,每3个结点抽1个,每层索引的结点数:
n/3,n/9,n/27,…,9,3,1
把它们累加起来求和也是收敛,空间复杂度是O(n),比起原始链表空间复杂度要多不少。
工程应用
LRU缓存机制
Redis - Skip List:跳跃表、为啥 Redis 使用跳表(Skip List)而不是使用 Red-Black?