<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://royqh.spaces.live.com/mmm2008-07-24_12.50/rsspretty.aspx?rssquery=en-US;http%3a%2f%2froyqh.spaces.live.com%2fcategory%2f%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>天上掉大饼之土人俗事: 数据结构</title><description /><link>http://royqh.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=cat%25E6%2595%25B0%25E6%258D%25AE%25E7%25BB%2593%25E6%259E%2584</link><language>en-US</language><pubDate>Sat, 11 Oct 2008 05:01:04 GMT</pubDate><lastBuildDate>Sat, 11 Oct 2008 05:01:04 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><cf:parentRSS>http://royqh.spaces.live.com/blog/feed.rss</cf:parentRSS><live:type>blogcategory</live:type><live:identity><live:id>-3180137652934690665</live:id><live:alias>royqh</live:alias></live:identity><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>快速排序的划分算法说明</title><link>http://royqh.spaces.live.com/Blog/cns!D3DDE1A75BFBB897!195.entry</link><description>&lt;div&gt;25号要考数据结构，这阵子正在恶补中。话说昨天看到快速排序这一块儿，终于把过去一直没搞清楚的部分算法搞清楚了，趁着还没忘赶紧记下来，以后可以回来看看，呵呵。&lt;/div&gt;
&lt;div&gt;快速排序算法的思想很简单，其实现也不复杂。但是它所用到的划分算法，即如何调整数列中的数据使之分别排列在预先选定的关键字两侧（如下图所示），乍一看确实不容易搞清楚。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;原始数列：&lt;/div&gt;
&lt;div&gt;89 74 18 83 58 99 4 70 3&lt;br&gt;选定58作为关键字，则经过划分算法调整之后得到的新数列为&lt;br&gt;（3 4 18） 58（ 89 99 83 70 74）&lt;/div&gt;
&lt;div&gt;比关键字58小的数据都在它左侧，而比它大的数据都在它右侧&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;先把划分算法的C语言实现放在这里，接下来我们以上面那个数列为例子，逐条语句来解释它。&lt;/div&gt;
&lt;div&gt;int partition(int *a ,int low, int high) {&lt;br&gt; int keyPos=(low+high)/2;&lt;br&gt; swapInt(a[keyPos],a[low]);&lt;br&gt; int key=a[low];&lt;br&gt; while (low&amp;lt;high) {&lt;br&gt;  while ((low&amp;lt;high) &amp;amp;&amp;amp; (key&amp;lt;=a[high])) high--;&lt;br&gt;  a[low]=a[high];&lt;br&gt;  while ((low&amp;lt;high) &amp;amp;&amp;amp; (a[low]&amp;lt;=key)) low++;&lt;br&gt;  a[high]=a[low];&lt;br&gt; }&lt;br&gt; a[low]=key; &lt;br&gt; return low;&lt;br&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;首先来看看 int keyPos=(low+high)/2; 是做什么的。划分算法的第一步是在数列中选定关键字，关键字选取的好坏决定着快速排序算法的实际效率。在这里，我们只是简单的选取数列最中间（其数组下标即为(low+high)/2）的数字作为关键字。在例子中，数列中一共有9项，故low应为0,high应为，keyPos=4，即关键字为第5条数据，为58。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;接下来是swapInt(a[keyPos],a[low])。swapInt的作用是交换两个变量的值，这里省略了它的具体实现。这一步将选定的关键字交换到了数列的开头，这一步很关键，在算法下面步骤的说明中我们将更好的认识到这一点。&lt;/div&gt;
&lt;div&gt;经过这一步后数列变为&lt;/div&gt;
&lt;div&gt;58 74 18 83 89 99 4 70 3&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;（这里插一句，在谭浩强的数据结构书里，是直接取a[low]作为关键字的，所以就省去了计算下标和swap的步骤，但是swap这一步对于理解整个算法过程恰恰是很关键的。因此，我不得不说，老谭这本书其实写得不咋地。在此推荐一本《数据结构与算法分析（C++版）》（第二版）&lt;a href="http://www.dangdang.com/product_detail/product_detail.asp?product_id=571954"&gt;http://www.dangdang.com/product_detail/product_detail.asp?product_id=571954&lt;/a&gt;，英文有一定基本的不妨直接看看，比国内那几本好太多了）。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;然后是key=a[low]。这一步保存已经交换到数列开头的关键字。这是因为在接下来的步骤里关键字会被不断覆盖，所以必须先保存起来，最后再恢复。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;循环这一块儿比较清楚，就是从两端向内移动low和high指针，直到low&amp;gt;=high为止。等会儿我们可以看到，循环结束时low正好关键字应该在的位置上。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;循环里面是最关键的部分，4条语句的顺序一定不能搞错了。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;先看看第一条，while ((low&amp;lt;high) &amp;amp;&amp;amp; (key&amp;lt;=a[high])) high--;&lt;/div&gt;
&lt;div&gt;就是从数列的后端向前找第一个小于关键字的数据所在的位置。&lt;/div&gt;
&lt;div&gt;在例子中，第一次循环时执行过程是这样的（下划线为high所指位置）：&lt;/div&gt;
&lt;div&gt;58 74 18 83 89 99 4 70 &lt;u&gt;3&lt;/u&gt;&lt;/div&gt;
&lt;div&gt;由于恰好最末一位就比关键字58小，所以语句执行完毕时high还是8。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;接下来执行第二条语句。&lt;/div&gt;
&lt;div&gt;a[low]=a[high]&lt;/div&gt;
&lt;div&gt;在执行它之前，a[low]中放的是什么呢？是关键字58。由于执行完前一步时，a[high]小于关键字a[low]，所以应该调整顺序，将它们两个交换。即应该swapInt(a[low],a[high]).但是由于我们在进入循环前已经保存过关键字a[low]的值，所以为了减少赋值操作，只需要把a[high]赋给a[low]，并记住此时关键字在a[high]就行了。&lt;/div&gt;
&lt;div&gt;执行之后的结果如下所示（*代表关键字所在位置）&lt;/div&gt;
&lt;div&gt;&lt;u&gt;3&lt;/u&gt; 74 18 83 89 99 4 70 *&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;然后第三条语句，while ((low&amp;lt;high) &amp;amp;&amp;amp; (a[low]&amp;lt;=key)) low++;&lt;/div&gt;
&lt;div&gt;从前向后找第一个比关键字大的数。&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;u&gt;3&lt;/u&gt; 74 18 83 89 99 4 70 *&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;3 &lt;u&gt;74&lt;/u&gt; 18 83 89 99 4 70 *&lt;/div&gt;
&lt;div&gt;OK，执行完后low=1,a[1]=74大于关键字58，顺序不对，应该调整，交换关键字和a[low]&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;此时a[high]是关键字，所以应该交换a[high]和a[low]。但由于和前一次赋值一样的简化理由，这里只需将a[low]赋给a[high]，然后记住现在关键字在a[low]即可。&lt;/div&gt;
&lt;div&gt;这就我们的是第四条语句：&lt;/div&gt;
&lt;div&gt;a[high]=a[low]。&lt;/div&gt;
&lt;div&gt;此时&lt;/div&gt;
&lt;div&gt;3 * 18 83 89 99 4 70 &lt;u&gt;74&lt;/u&gt;&lt;/div&gt;
&lt;div&gt;&lt;u&gt;&lt;/u&gt; &lt;/div&gt;
&lt;div&gt;到这里应该已经可以看出来了，在整个循环中，low和high不断交替指向关键字和需要调整顺序的变量。通过反复的交换，最终关键字移到了合适的位置，其左边的数据都比它小&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;第二次循环&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;3 * 18 83 89 99 &lt;u&gt;4&lt;/u&gt; 70 74&lt;/div&gt;
&lt;div&gt;3 &lt;u&gt;4&lt;/u&gt; 18 83 89 99 * 70 74&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;3 4 18 &lt;u&gt;83&lt;/u&gt; 89 99 * 70 74&lt;/div&gt;
&lt;div&gt;3 4 18 * 89 99 &lt;u&gt;83&lt;/u&gt;  70 74&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;第三次循环&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;3 4 18 &lt;u&gt;*&lt;/u&gt; 89 99 83 70 74&lt;/div&gt;
&lt;div&gt;3 4 18 &lt;u&gt;*&lt;/u&gt; 89 99 83 70 74&lt;/div&gt;
&lt;div&gt;3 4 18 &lt;u&gt;*&lt;/u&gt; 89 99 83 70 74&lt;/div&gt;
&lt;div&gt;3 4 18 &lt;u&gt;*&lt;/u&gt; 89 99 83 70 74&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;满足循环结束条件，循环结束。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;此时关键字应该在a[low]中，而由于在上面的处理中a[low]已经被覆盖过，所以需要重新恢复关键字的值，即 a[low]=key; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;这样，划分处理算法就完成了。我的说明也完了，就是不知道别人看了能不能看明白，咔咔&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-3180137652934690665&amp;page=RSS%3a+%e5%bf%ab%e9%80%9f%e6%8e%92%e5%ba%8f%e7%9a%84%e5%88%92%e5%88%86%e7%ae%97%e6%b3%95%e8%af%b4%e6%98%8e&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=royqh.spaces.live.com&amp;amp;GT1=royqh"&gt;</description><comments>http://royqh.spaces.live.com/Blog/cns!D3DDE1A75BFBB897!195.entry#comment</comments><guid isPermaLink="true">http://royqh.spaces.live.com/Blog/cns!D3DDE1A75BFBB897!195.entry</guid><pubDate>Tue, 20 Dec 2005 06:03:15 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://royqh.spaces.live.com/blog/cns!D3DDE1A75BFBB897!195/comments/feed.rss</wfw:commentRss><wfw:comment>http://royqh.spaces.live.com/Blog/cns!D3DDE1A75BFBB897!195.entry#comment</wfw:comment><dcterms:modified>2005-12-20T06:58:56Z</dcterms:modified></item></channel></rss>