写在前面的话
跳表实际上是一种非常好使的数据结构,但由于用的人比较少,所以在OI竞赛中并不常用,但其效率是很高的。想要深入研究的同学可以研究:
- 《让算法的效率“跳起来”! 》—— 魏冉
- 《线段跳表——跳表的一个拓展》——李骥扬
这两位大神的论文
跳表的定义
- 跳表的每一层都是一个链表
- 每一条链表的两端必须是 −∞ 和 +∞
- 每条链的元素必须包含于序数较低的链的元素集合
下图是一个链表
跳表的搜索操作
跳表的普通搜索操作
设当前结点为
u
,待搜索的数为
跳表的搜索过程如下:
- 如果
u=t
,搜索结束,当前位置即为搜索结果
- 如果
u
的右结点不大于
- 如果
u
的右结点大于
- 如果
u
的右结点大于
举一个例子:在上图中的跳表中搜索6
跳表的记忆化搜索操作
跳表的记忆化搜索就是在普通搜索的基础上,提取出上一次搜索的每一层的最后一个结点,比如讲上述搜索例子中提取可以得到:
其中橙色结点为每一层的末端。
之后我们找到第一个小于待搜索元素的末端结点,从该结点开始搜索,例如搜索 5 这个元素:
首先找到起始结点:
然后搜索:
这种搜索方式在前后搜索数据有关联的时候尤为管用
跳表的插入操作
跳表的插入分为三步:
- 搜索待插入元素
- 在搜索结束的地方插入
- 由随机决策模块决定新元素的层数,并向上加层
例如在下图链表中添加元素15:
搜索后得到待插入元素的位置:
插入后运行随即决策模块得到层数,比如说是3层,则需要向上增加层数:
于是我们就成功地将15插入到了这个跳表之中。
然后我们来看随即决策模块
给定一个常数P
H <- 0
While True
R <- random(0~1)
If R < P Then
H++
Else Do
Break
End
在这个随机决策模块中,我们是从H层按P的概率向上增加层数,所以很容易得到一个性质:
对于一个元素,它所在列的高度大于等于 k 的概率为
Pk−1
这个重要的性质将会在分析复杂度的时候反复用到。
跳表的删除操作
删除操作就是先查找,找到后删掉,举个例子,在下图的跳表中删除元素9: