跳跃表GydF4y2Ba
跳跃列表是GydF4y2Baprobabilisitc数据结构GydF4y2Ba这是建立在GydF4y2Ba链表GydF4y2Ba. 跳过列表使用概率在原始链表的基础上构建链表的后续层。每个附加的链接层包含较少的元素,但不包含新元素。GydF4y2Ba
你可以把跳过列表想象成地铁系统。每一站都有一列火车停。不过,也有特快列车。这列火车不会停靠任何独特的站点,但会停靠较少的站点。如果你知道特快列车在哪里停的话,这使它成为一个很有吸引力的选择。GydF4y2Ba
跳跃列表是非常有用的,当你需要能够同时访问你的数据结构。想象一下A.GydF4y2Ba红黑树GydF4y2Ba,的实现GydF4y2Ba二叉搜索树GydF4y2Ba. 如果您在红黑树中插入一个新节点,您可能需要重新平衡整个过程,并且在此过程中您将无法访问数据。在跳过列表中,如果必须插入新节点,则只有相邻节点会受到影响,因此在发生这种情况时,您仍然可以访问大部分数据。GydF4y2Ba
内容GydF4y2Ba
性质GydF4y2Ba
跳过列表从一个基本的、有序的链表开始。此列表已排序,但我们无法对其进行二进制搜索,因为它是一个链接列表,无法索引到其中。但订购单稍后会派上用场。GydF4y2Ba
然后,在底部列表的顶部添加另一层。该新层将以概率包含前一层中的任何给定元素GydF4y2Ba 此概率可以不同,但通常情况下GydF4y2Ba 用来。另外,在该链接的表的第一个节点通常总是保持,作为新层的报头。看看下面的图形,看到一些元素是如何保持,但其他人将被丢弃。在这里,正巧元素的一半都保存在每一个新的层,但它可能是或多或少 - 它是所有概率。在所有的情况下,每一个新的层依然有序。GydF4y2Ba
跳跃列表GydF4y2Ba 有在其分析中引用的几个重要特性。它的高度GydF4y2Ba 这是其中链接列表的数量。它有许多不同的元素,GydF4y2Ba 这是有可能的GydF4y2Ba 这通常是GydF4y2Ba
(出现在大多数列表之一)最高的元素将出现在GydF4y2Ba 列表,平均 - we'll证明了这一点GydF4y2Ba后来GydF4y2Ba. 如果我们使用GydF4y2Ba ,有GydF4y2Ba 列表。这是平均值GydF4y2Ba . “链表中的每个元素都在它下面的链表中”的另一种说法是“级别中的每个元素”GydF4y2Ba 存在于水平面GydF4y2Ba "GydF4y2Ba
跳过列表中的每个元素都有四个指针。它指向节点的左侧、右侧、顶部和底部。这些GydF4y2Ba四节点GydF4y2Ba将使我们能够有效地通过跳跃列表搜索。GydF4y2Ba
时间和空间复杂GydF4y2Ba
时间GydF4y2Ba
该跳跃列表的复杂性,由于其概率性质复杂。我们将证明它的时间复杂度GydF4y2Ba以下GydF4y2Ba,但现在我们只看结果。但需要注意的是,这些界限是GydF4y2Ba预期GydF4y2Ba或者GydF4y2Ba平均情况GydF4y2Ba界限。这是因为我们在该数据结构中使用随机化:GydF4y2Ba
这个GydF4y2Ba最差的情况GydF4y2Ba对于跳跃列表范围低于,但我们不会担心这些分析:GydF4y2Ba
空间GydF4y2Ba
空间是比较容易推理一点。假设我们有我们的跳跃列表中的位置的总数等于GydF4y2Ba
这等于GydF4y2Ba
因为无限的总和。因此,我们预期的空间利用率是根本GydF4y2Ba
这也不是具体的。概率,我们跳跃列表可以长高得多。然而,这是预期的空间复杂度。GydF4y2Ba
算法伪代码GydF4y2Ba
有在跳跃列表四个主要业务。GydF4y2Ba
搜寻GydF4y2Ba
此功能的输入是一个搜索键,GydF4y2Ba钥匙GydF4y2Ba
.该函数的输出是一个位置,GydF4y2BaPGydF4y2Ba
,使此位置的值为小于或等于的最大值GydF4y2Ba钥匙GydF4y2Ba
.GydF4y2Ba
1 2 3 4 5 6 7GydF4y2Ba |
|
基本上,我们是向下扫描跳过列表,然后向前扫描。GydF4y2Ba
索引GydF4y2Ba
其作用方式与GydF4y2Ba搜寻GydF4y2Ba
,因此我们将省略该代码。GydF4y2Ba
插入GydF4y2Ba
用于插入的输入是一GydF4y2Ba钥匙GydF4y2Ba
.输出是最顶部位置,GydF4y2BaPGydF4y2Ba
在其中输入被插入。请注意,我们使用的是GydF4y2Ba搜寻GydF4y2Ba
方法从上面。我们使用一个名为GydF4y2BaCoinFlip()GydF4y2Ba
模仿一个公平的硬币,并返回无论是正面还是反面。最后,函数GydF4y2Ba插入者(a,b)GydF4y2Ba
只需插入节点GydF4y2BaA.GydF4y2Ba
该节点后GydF4y2BaBGydF4y2Ba
.GydF4y2Ba
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16GydF4y2Ba |
|
首先,我们总是插入GydF4y2Ba钥匙GydF4y2Ba
在正确的位置进入底部列表。然后,我们必须GydF4y2Ba促进GydF4y2Ba新的元素。我们通过一个翻转公平的硬币这样做。如果出现正面,我们提倡的新元素。通过这种翻转公平的硬币,我们实际上是在决定如何大,使塔新元素。我们从位置向后扫描,直到我们可以上去,然后我们去了一个级别,并插入我们GydF4y2Ba钥匙GydF4y2Ba
就在我们现在的位置之后。GydF4y2Ba
虽然我们翻动的纪念币,如果头的数量开始增长比我们当前高度较大,我们必须确保建立在我们的跳跃列表一个新的水平,以适应这一点。此功能照顾的那行7-9对我们来说。GydF4y2Ba
删除GydF4y2Ba
删除利用了GydF4y2Ba搜寻GydF4y2Ba
操作比简单GydF4y2Ba插入GydF4y2Ba
活动我们将通过更详细地编写伪代码来节省空间。GydF4y2Ba
1 2 3 4 5 6GydF4y2Ba |
|
删除可以通过多种方式实现。因为我们知道什么时候我们第一次发现GydF4y2Ba钥匙GydF4y2Ba
,它将连接到的所有其他实例GydF4y2Ba钥匙GydF4y2Ba
,我们可以很容易地删除它们一次。GydF4y2Ba
跳跃列表的高度GydF4y2Ba
早些时候,我们说会有GydF4y2Ba 列出总。但为什么?如果每个新创建的水平是这样做概率,我们怎么能知道?GydF4y2Ba
的概率GydF4y2Ba 在跳跃列表元素GydF4y2Ba 具有GydF4y2Ba 所有元素都达到了标准GydF4y2Ba 只是GydF4y2Ba
因为如果概率GydF4y2Ba 然后,为了创建一个新的关卡,我们为每个元素投掷一枚硬币,看看它是否应该包括在内。那么,在GydF4y2Ba至少一个GydF4y2Ba的GydF4y2Ba 元素达到水平GydF4y2Ba 是GydF4y2Ba
让我们试着用一些数字来看看这意味着什么。如果GydF4y2Ba 然后GydF4y2Ba
如果GydF4y2Ba 增加稍微GydF4y2Ba 那么GydF4y2Ba
这意味着,如果GydF4y2Ba ,有GydF4y2Ba百万分之一GydF4y2Ba任何一个特定元素到达顶层的几率。当然,这种分析并不严格,但概率很高(这个词经常在随机算法中使用),GydF4y2Ba 具有高度GydF4y2Ba .GydF4y2Ba
证明复杂性GydF4y2Ba
如前所述,跳过列表的最坏情况非常糟糕。事实上,跳过列表的高度可以向GydF4y2Ba
因为我们使用的是随机抛硬币。然而,这种分析是不公平的,因为跳过列表的平均性能要好得多。让我们做手术吧GydF4y2Ba搜寻GydF4y2Ba
. 这是跳过列表的主要焦点,因为GydF4y2Ba插入GydF4y2Ba
和GydF4y2Ba删除GydF4y2Ba
事实也证明了这一点。GydF4y2Ba
搜寻GydF4y2Ba
有两个嵌套GydF4y2Ba尽管GydF4y2Ba
在这个函数循环。外部循环类似于“向下扫描”跳跃表,内部循环类似于“向前扫描”跳跃表。GydF4y2Ba
我们已经证明GydF4y2Ba在上面GydF4y2Ba那是高度吗GydF4y2Ba 跳跃列表是GydF4y2Ba 因此,向下跳跃列表,我们可以使移动的最大数量为GydF4y2Ba
现在,让我们结合扫描次数未来,我们可以做到的。比方说,我们扫描GydF4y2Ba 钥匙在一级GydF4y2Ba 在我们下降到水平之前GydF4y2Ba . 我们进入该级别后扫描的每个后续键都不能存在于该级别中GydF4y2Ba ,否则我们早就看到了。可能性GydF4y2Ba任何GydF4y2Ba此级别中的给定键在级别中GydF4y2Ba 是GydF4y2Ba 这意味着,我们在新的关卡中遇到的预期键数是2,aGydF4y2Ba 手术。GydF4y2Ba
所以,我们的扫描下来,向前扫描采取两个步骤GydF4y2Ba 和GydF4y2Ba 时间分别。这意味着我们的总时间搜索GydF4y2Ba
如果这种分析与GydF4y2Ba二叉搜索树GydF4y2Ba,这是因为它是!如果你在跳跃列表仔细一看,它就像一棵树,用较低水平高于水平大。GydF4y2Ba
参考文献GydF4y2Ba
- 穆拉,W。GydF4y2Ba维基百科跳跃列表GydF4y2Ba. 恢复April 20, 2016, fromhttps://en.wikipedia.org/wiki/Skip_listGydF4y2Ba