<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>数据结构 on lfkdsk's Blog</title><link>https://blog.lfkdsk.org/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</link><description>Recent content in 数据结构 on lfkdsk's Blog</description><generator>Hugo</generator><language>cn</language><lastBuildDate>Mon, 11 Sep 2017 23:52:38 +0000</lastBuildDate><atom:link href="https://blog.lfkdsk.org/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/index.xml" rel="self" type="application/rss+xml"/><item><title>快速了解 SkipList</title><link>https://blog.lfkdsk.org/quick-learn-skip-list/</link><pubDate>Mon, 11 Sep 2017 23:52:38 +0000</pubDate><guid>https://blog.lfkdsk.org/quick-learn-skip-list/</guid><description>&lt;h1 id="快速的-skiplist-实现教程">快速的 SkipList 实现教程&lt;/h1>
&lt;blockquote>
&lt;p>在计算机科学领域，&lt;strong>跳跃链表&lt;/strong>是一种&lt;a href="https://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84">数据结构&lt;/a>，允许快速查询一个&lt;a href="https://zh.wikipedia.org/wiki/%E5%BA%8F%E5%88%97">有序连续&lt;/a>元素的数据链表。快速查询是通过维护一个多层次的链表，且每一层链表中的元素是前一层链表元素的子集。&lt;/p>
&lt;p>基于并联的&lt;a href="https://zh.wikipedia.org/wiki/%E9%93%BE%E8%A1%A8">链表&lt;/a>，其&lt;a href="https://zh.wikipedia.org/w/index.php?title=%E6%95%88%E7%8E%87&amp;amp;action=edit&amp;amp;redlink=1">效率&lt;/a>可比拟于&lt;a href="https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%8F%89%E6%9F%A5%E6%89%BE%E6%A0%91">二叉查找树&lt;/a>（对于大多数操作需要&lt;a href="https://zh.wikipedia.org/wiki/%E5%A4%A7O%E7%AC%A6%E5%8F%B7">O&lt;/a>(log &lt;em>n&lt;/em>)平均时间）。&lt;/p>
&lt;p>基本上，跳跃列表是对有序的&lt;a href="https://zh.wikipedia.org/wiki/%E9%93%BE%E8%A1%A8">链表&lt;/a>增加上附加的前进链接，增加是以&lt;a href="https://zh.wikipedia.org/w/index.php?title=Randomization&amp;amp;action=edit&amp;amp;redlink=1">随机化&lt;/a>的方式进行的，所以在列表中的查找可以快速的跳过部分列表，因此得名。所有操作都以对数随机化的时间进行。
&lt;img src="https://blog.lfkdsk.org/quick-learn-skip-list/skip-list.png" alt="skip">&lt;/p>
&lt;p>要查找一个目标元素，起步于头元素和顶层列表，并沿着每个链表搜索，直到到达小于或着等于目标的最后一个元素。通过跟踪起自目标直到到达在更高列表中出现的元素的反向查找路径，在每个链表中预期的步数显而易见是 1/&lt;em>p&lt;/em>。所以查找的总体代价是 O((log1/&lt;em>p&lt;/em> n) / p)，当&lt;em>p&lt;/em> 是常数时是 O(log &lt;em>n&lt;/em>)。通过选择不同 &lt;em>p&lt;/em> 值，就可以在查找代价和存储代价之间作出权衡。&lt;/p>
&lt;p>插入和删除的实现非常像相应的链表操作，除了&amp;quot;高层&amp;quot;元素必须在多个链表中插入或删除之外。&lt;/p>
&lt;p>跳跃列表不像某些传统&lt;a href="https://zh.wikipedia.org/wiki/%E5%B9%B3%E8%A1%A1%E6%A0%91">平衡树&lt;/a>数据结构那样提供绝对的最坏情况性能保证，因为用来建造跳跃列表的扔硬币方法总有可能（尽管概率很小）生成一个糟糕的不平衡结构。但是在实际中它工作的很好，随机化平衡方案比在平衡二叉查找树中用的确定性平衡方案容易实现。跳跃列表在&lt;a href="https://zh.wikipedia.org/wiki/%E5%B9%B6%E8%A1%8C%E8%AE%A1%E7%AE%97">并行计算&lt;/a>中也很有用，这里的插入可以在跳跃列表不同的部分并行的进行，而不用全局的数据结构重新平衡。&lt;/p>
&lt;p>​																			—— Wikipedia&lt;/p>
&lt;/blockquote>
&lt;p>以上就是 Wikipedia 中对 SkipList 的描述，从描述中和以往的了解我们可以得知，SkipList 是对 List 的一种加强，通过拔高某些 Node 的层次来达到快速搜索的目的，根据这个想法我们可以知道，这个有点类似于躺平的二叉搜索树，这套 &lt;em>快速实现教程&lt;/em> 的目的，就是截取文章中讨论内容的重点部分，通过重点讨论其中的精要部分来达到快速实现的目的。&lt;/p>
&lt;h2 id="搜索方法">搜索方法&lt;/h2>
&lt;p>我们知道 SkipList 的结构知道我们就知道应该怎么对这个东西进行搜索，首先是从最上层的开始搜索，根据 &lt;strong>Key&lt;/strong> 的比较进行判断向哪个方向进行搜索：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> SkipListNode&lt;span style="color:#f92672">&amp;lt;&lt;/span>K, V&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#a6e22e">findNodeByKey&lt;/span>(K key) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> SkipListNode&lt;span style="color:#f92672">&amp;lt;&lt;/span>K, V&lt;span style="color:#f92672">&amp;gt;&lt;/span> head &lt;span style="color:#f92672">=&lt;/span> headNode;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">while&lt;/span> (&lt;span style="color:#66d9ef">true&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 首先右侧节点不为空 并且当前节点比右侧节点大 ===&amp;gt; 我们可以往右侧进行查找&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">while&lt;/span> (head.&lt;span style="color:#a6e22e">right&lt;/span>.&lt;span style="color:#a6e22e">key&lt;/span> &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span> &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> key.&lt;span style="color:#a6e22e">compareTo&lt;/span>(head.&lt;span style="color:#a6e22e">right&lt;/span>.&lt;span style="color:#a6e22e">key&lt;/span>) &lt;span style="color:#f92672">&amp;gt;=&lt;/span> 0) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> head &lt;span style="color:#f92672">=&lt;/span> head.&lt;span style="color:#a6e22e">right&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		 &lt;span style="color:#75715e">// 向下查找 ===&amp;gt; 直到最下一层&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (head.&lt;span style="color:#a6e22e">down&lt;/span> &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> head &lt;span style="color:#f92672">=&lt;/span> head.&lt;span style="color:#a6e22e">down&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">break&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> head;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>根据 &lt;strong>从左到右，从上到下&lt;/strong> 的方法，我们就能查找到对应的节点，如果本身 List 中没有对应的节点，我们会获得 &lt;strong>比所搜索的 Key 最小的一个节点&lt;/strong> 这样我们无论是存放还是搜索都很方便。&lt;/p></description></item></channel></rss>