<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>waimv.com &#187; DataStruct</title>
	<atom:link href="http://www.waimv.com/category/datastruct/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.waimv.com</link>
	<description></description>
	<lastBuildDate>Fri, 09 Nov 2018 10:41:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>SkipList 跳表</title>
		<link>http://www.waimv.com/datastruct/270/</link>
		<comments>http://www.waimv.com/datastruct/270/#comments</comments>
		<pubDate>Fri, 14 Jun 2013 03:34:57 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[DataStruct]]></category>
		<category><![CDATA[skiplist]]></category>

		<guid isPermaLink="false">http://www.szpian.com/?p=270</guid>
		<description><![CDATA[来源：http://kenby.iteye.com/blog/1187303]]></description>
			<content:encoded><![CDATA[<div id="blog_content">
<h2>为什么选择跳表</h2>
<p>目前经常使用的平衡数据结构有：B树，红黑树，AVL树，Splay Tree, Treep等。</p>
<p>想象一下，给你一张草稿纸，一只笔，一个编辑器，你能立即实现一颗红黑树，或者AVL树</p>
<p>出来吗？ 很难吧，这需要时间，要考虑很多细节，要参考一堆算法与数据结构之类的树，</p>
<p>还要参考网上的代码，相当麻烦。</p>
<p>用跳表吧，跳表是一种随机化的数据结构，目前开源软件 Redis 和 LevelDB 都有用到它，</p>
<p>它的效率和红黑树以及 AVL 树不相上下，但跳表的原理相当简单，只要你能熟练操作链表，</p>
<p>就能轻松实现一个 SkipList。</p>
<h2>有序表的搜索</h2>
<p>考虑一个有序表：<br />
<img src="http://dl.iteye.com/upload/attachment/565643/d5d03b36-abff-34ea-9c40-a1fbfb709a81.jpg" alt="" /></p>
<p>从该有序表中搜索元素 &lt; 23, 43, 59 &gt; ，需要比较的次数分别为 &lt; 2, 4, 6 &gt;，总共比较的次数</p>
<p>为 2 + 4 + 6 = 12 次。有没有优化的算法吗?  链表是有序的，但不能使用二分查找。类似二叉</p>
<p>搜索树，我们把一些节点提取出来，作为索引。得到如下结构：<br />
<img src="http://dl.iteye.com/upload/attachment/565648/7c904c3f-1f39-31af-b8cd-b6de27a94061.jpg" alt="" /><br />
这里我们把 &lt; 14, 34, 50, 72 &gt; 提取出来作为一级索引，这样搜索的时候就可以减少比较次数了。</p>
<p>我们还可以再从一级索引提取一些元素出来，作为二级索引，变成如下结构：</p>
<p><img src="http://dl.iteye.com/upload/attachment/565666/96983cb0-d60a-31da-953d-2dde4036ea6b.jpg" alt="" /></p>
<p>这里元素不多，体现不出优势，如果元素足够多，这种索引结构就能体现出优势来了。</p>
<h2>跳表</h2>
<p>下面的结构是就是跳表：</p>
<p>其中 -1 表示 INT_MIN， 链表的最小值，1 表示 INT_MAX，链表的最大值。</p>
<p><img title="点击查看原始大小图片" src="http://dl.iteye.com/upload/attachment/565664/f4c149bd-d8ea-39ff-813f-93d809c90966.jpg" alt="" width="700" height="232" /></p>
<p>跳表具有如下性质：</p>
<p>(1) 由很多层结构组成</p>
<p>(2) 每一层都是一个有序的链表</p>
<p>(3) 最底层(Level 1)的链表包含所有元素</p>
<p>(4) 如果一个元素出现在 Level i 的链表中，则它在 Level i 之下的链表也都会出现。</p>
<p>(5) 每个节点包含两个指针，一个指向同一链表中的下一个元素，一个指向下面一层的元素。</p>
<h2>跳表的搜索</h2>
<p><img title="点击查看原始大小图片" src="http://dl.iteye.com/upload/attachment/565682/ec9fd643-f85c-3072-8634-60cfc88ab334.jpg" alt="" width="700" height="201" /></p>
<p>例子：查找元素 117</p>
<p>(1) 比较 21， 比 21 大，往后面找</p>
<p>(2) 比较 37,   比 37大，比链表最大值小，从 37 的下面一层开始找</p>
<p>(3) 比较 71,  比 71 大，比链表最大值小，从 71 的下面一层开始找</p>
<p>(4) 比较 85， 比 85 大，从后面找</p>
<p>(5) 比较 117， 等于 117， 找到了节点。</p>
<p>具体的搜索算法如下：</p>
<div>
<div>
<div>C代码  <a title="收藏这段代码"><img src="http://kenby.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div>
</div>
<ol>
<li>/* 如果存在 x, 返回 x 所在的节点，</li>
<li> * 否则返回 x 的后继节点 */</li>
<li>find(x)</li>
<li>{</li>
<li> p = top;</li>
<li> while (1) {</li>
<li> while (p-&gt;next-&gt;key &lt; x)</li>
<li> p = p-&gt;next;</li>
<li> if (p-&gt;down == NULL)</li>
<li> return p-&gt;next;</li>
<li> p = p-&gt;down;</li>
<li> }</li>
<li>}</li>
</ol>
</div>
<h2>跳表的插入</h2>
<p>先确定该元素要占据的层数 K（采用丢硬币的方式，这完全是随机的）</p>
<p>然后在 Level 1 &#8230; Level K 各个层的链表都插入元素。</p>
<p>例子：插入 119， K = 2<br />
<img title="点击查看原始大小图片" src="http://dl.iteye.com/upload/attachment/565696/bb72be16-6162-3fee-b680-311f25dd7c3a.jpg" alt="" width="700" height="197" /></p>
<p>如果 K 大于链表的层数，则要添加新的层。</p>
<p>例子：插入 119， K = 4<br />
<img title="点击查看原始大小图片" src="http://dl.iteye.com/upload/attachment/565698/6eac083f-45d9-37f9-867f-0d709d9659d3.jpg" alt="" width="700" height="216" /></p>
<h2>丢硬币决定 K</h2>
<p>插入元素的时候，元素所占有的层数完全是随机的，通过一下随机算法产生：</p>
<div>
<div>
<div>C代码  <a title="收藏这段代码"><img src="http://kenby.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div>
</div>
<ol>
<li>int random_level()</li>
<li>{</li>
<li> K = 1;</li>
<li> while (random(0,1))</li>
<li> K++;</li>
<li> return K;</li>
<li>}</li>
</ol>
</div>
<p>相当与做一次丢硬币的实验，如果遇到正面，继续丢，遇到反面，则停止，</p>
<p>用实验中丢硬币的次数 K 作为元素占有的层数。显然随机变量 K 满足参数为 p = 1/2 的几何分布，</p>
<p>K 的期望值 E[K] = 1/p = 2. 就是说，各个元素的层数，期望值是 2 层。</p>
<h2>跳表的高度。</h2>
<p>n 个元素的跳表，每个元素插入的时候都要做一次实验，用来决定元素占据的层数 K，</p>
<p>跳表的高度等于这 n 次实验中产生的最大 K，待续。。。</p>
<h2>跳表的空间复杂度分析</h2>
<p>根据上面的分析，每个元素的期望高度为 2， 一个大小为 n 的跳表，其节点数目的</p>
<p>期望值是 2n。</p>
<h2>跳表的删除</h2>
<p>在各个层中找到包含 x 的节点，使用标准的 delete from list 方法删除该节点。</p>
<p>例子：删除 71<br />
<img title="点击查看原始大小图片" src="http://dl.iteye.com/upload/attachment/565721/7bab9ad1-9f5a-37d0-bc38-89ee50d1bc0d.jpg" alt="" width="700" height="198" /></p>
</div>
<div>
<ul>
<li><a href="http://kenby.iteye.com/blog/1187303#">查看图片附件</a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.waimv.com/datastruct/270/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
