跳表瞎写

我看其他人都已经卷成什么样了就我还在颓这种无意义的东西((

感觉在复读 OI-wiki


初中的时候好像谁跟我提到过这玩意儿?


先引一段 OI-wiki 上的话:

跳表(Skip List)是由 William Pugh 发明的一种查找数据结构,支持对数据的快速查找,插入和删除。

是不是感觉和平衡树挺像的

优势在于简单好写好想不容易写错

不过这玩意儿应该做不了文艺平衡树那套东西,顶多当个 std::map

但现在都 1202 年了, STL 早就能用了

所以这玩意儿更没用了


接下来我们都认为跳表干的就是 std::map 干的事,因此有一个 $(index, value)$ 的 std::pair 的说法

首先得知道这东西是怎么建出来的

我们先看看我们平时支持插入删除的东西是什么

假设我们不会平衡树,那就用链表!

但是链表的各种东西似乎都是 $O(n)$ 的?(大悲

考虑链表的劣势在于我们没有合并多个信息

那就合并嘛,直接倍增就好了嘛

不过这个序列是动态的,插入删除什么的倍增怎么处理?

处理不了吧,很蓝的啦

当然这东西要是能定期重构那我也没话说

不过思路显然还是对的,我们确实需要找一种这样的方法,跳表就提供了一种合并信息而且支持动态的方法,挺高妙的


跳表在有序链表的基础上,引入了一个 “分层” 的概念

就是说一个结点可能有很多层,每一层存储它该层的后继(可能还有前驱)

换言之就是有若干层有序链表,每一层都在下一层有所对应

感觉和分散层叠那家伙有点像((

然后分层的方式是随机化

对于一个点,每一次都有 $p$ 的概率向上加一层

显然建表的时候每一层的最后一个结点都是可以维护的,所以每一层按一个普通链表建就行

那么此时,我们对跳表进行修改查询等操作时,就可以从最高层开始,不断和倍增一样看看下一跳是否会超,不会超就直接在这一层跳,会超就往下一层走

这种带随机化的东西毛估估感觉复杂度是对的((


首先是空间复杂度,考虑对于一个结点,其层数为 $i$ 的概率是 $p^{i-1}(1-p)$

那么对于该结点的期望层数就是 $\sum_{i=1} ip^{i-1}(1-p)={1\over {1-p}}$

考虑 $p$ 是一个我们定下来的常数,总的期望空间复杂度就是 $O(n)$ 的

由于我们是随机化的,应该一般都能到达这个复杂度

另外显然 $O(\log n)$ 层以上其实用处不大,所以我们完全可以设个阈值表示大于这个阈值的层我们不要,这个阈值看起来一副取 $O(\log n)$ 的样子,那么空间复杂度就是 $O(n\log n)$ 的


然后是时间复杂度

我们直接考虑查询一个 $index \ge x$ 的结点,或者说 $x$ 的非严格后继

OI-wiki 中的说法是要不断往上爬爬到某一层,个人感觉直接把 head 结点赋一个最高的层数就行了,而且 OI-wiki 上的代码好像也是这么实现的?

考虑从最高层开始查,如果其后继结点 $index < x$ 显然可以直接跳,否则考虑下降一层

OI-wiki 上给了一个看不懂的东西

但是我们考虑这么跳的话,每一层结点个数期望减半,所以期望复杂度和倍增应该是相同的

于是复杂度就是 $O(\log n)$

插入同理

删除同理

好像就好了

看起来常数挺小的样子