跳表
跳表维护一个多层次的有序链表,每个链表都是下一层链表的子集
相比于红黑树,跳表在范围查找方面有着更好的支持
结构
在搜索过程中,现在最高层次的链表中进行搜索,当发现需要查找的元素在该层的两个相邻节点之间时,将跳转到下一层链表中进行搜索
上图中,假设我们要搜索值为6的节点,首先现在第一层进行搜索,在节点5处发现其取值在该节点和下一节点9之间,那么就往下遍历到下一层,发现其在5和7之间,继续往下,最终找到其为5节点的下一个节点。查找过程中,我们不需要遍历6节点之前的所有节点,查找效率得到了提升
可以发现,跳表使用的是空间换时间的方式提升效率,其搜索方式类似于二分查找,时间复杂度为O(logn)。假设跳表上一层的节点数是下一层的一半,则总节点数为 n + n / 2 + n / 4 + . . . + 4 + 2 = 2 n − 2 n+n/2+n/4+...+4+2=2n-2 n+n/2+n/4+...+4+2=2n−2,即空间复杂度为O(n)
插入数据
在跳表中插入数据时,应保持有序,其在最下层的的插入情况和普通链表一样,但若不更新索引容易造成退化
下图中4节点和9节点插入过多节点,然而上层索引链表没有及时更新,导致该段的搜索退化为普通链表
为了方便,跳表在链表中随机抽取 n / 2 n/2 n/2个节点来建立索引,而不是严格的每隔一个元素建立一个索引,这样的实现方式对查找效率的影响不大
代码实现上,可以实现一个随机函数randlevel()
,该函数会返回1~n之间的数,其中n为索引链表的最高层数,而1表示不建立索引。该函数返回1的概率为1/2,返回2的概率为1/4,返回n的概率为
1
/
2
n
1/2^n
1/2n
在插入时,首先生成随机数,然后再在查找插入位置的时候随着跳跃的过程而进行插入,比如下图中,插入元素6,随机函数结果为3,表示在插入的同时,上两层索引链表也要进行插入;在搜索插入位置时,最高层索引找到插入位置为19之间,然后向下进入下一层索引链表,并在第一层插入节点6,接着找到其在39之间,继续向下并插入,最后在4~7之间成功插入节点,并生成了索引节点。
删除数据
删除操作比插入要简单得多,只需要注意,在删除的过程中,需要将索引链表中的对应节点也一并删除