﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-C++世界-随笔分类-各类常用算法</title><link>http://www.cppblog.com/fdsajhg/category/14554.html</link><description>管理系统--&lt;</description><language>zh-cn</language><lastBuildDate>Sat, 14 Aug 2010 13:22:11 GMT</lastBuildDate><pubDate>Sat, 14 Aug 2010 13:22:11 GMT</pubDate><ttl>60</ttl><item><title>各种排序算法小结 </title><link>http://www.cppblog.com/fdsajhg/archive/2010/08/14/123442.html</link><dc:creator>傅先生</dc:creator><author>傅先生</author><pubDate>Sat, 14 Aug 2010 09:16:00 GMT</pubDate><guid>http://www.cppblog.com/fdsajhg/archive/2010/08/14/123442.html</guid><wfw:comment>http://www.cppblog.com/fdsajhg/comments/123442.html</wfw:comment><comments>http://www.cppblog.com/fdsajhg/archive/2010/08/14/123442.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fdsajhg/comments/commentRss/123442.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fdsajhg/services/trackbacks/123442.html</trackback:ping><description><![CDATA[<p>各种排序算法小结 排序算法是一种基本并且常用的算法。由于实际工作中处理的数量巨大，所以排序算法 <br>对算法本身的速度要求很高。 <br>而一般我们所谓的算法的性能主要是指算法的复杂度，一般用O方法来表示。在后面我将 <br>给出详细的说明。 </p>
<p>对于排序的算法我想先做一点简单的介绍，也是给这篇文章理一个提纲。 <br>我将按照算法的复杂度，从简单到难来分析算法。 <br>第一部分是简单排序算法，后面你将看到他们的共同点是算法复杂度为O(N*N)（因为没有 <br>使用word,所以无法打出上标和下标）。 <br>第二部分是高级排序算法，复杂度为O(Log2(N))。这里我们只介绍一种算法。另外还有几种 <br>算法因为涉及树与堆的概念，所以这里不于讨论。 <br>第三部分类似动脑筋。这里的两种算法并不是最好的（甚至有最慢的），但是算法本身比较 <br>奇特，值得参考（编程的角度）。同时也可以让我们从另外的角度来认识这个问题。 <br>第四部分是我送给大家的一个餐后的甜点——一个基于模板的通用快速排序。由于是模板函数 <br>可以对任何数据类型排序（抱歉，里面使用了一些论坛专家的呢称）。 </p>
<p>现在，让我们开始吧： </p>
<p>一、简单排序算法 <br>由于程序比较简单，所以没有加什么注释。所有的程序都给出了完整的运行代码，并在我的VC环境 <br>下运行通过。因为没有涉及MFC和WINDOWS的内容，所以在BORLAND C++的平台上应该也不会有什么 <br>问题的。在代码的后面给出了运行过程示意，希望对理解有帮助。 </p>
<p>1.冒泡法： <br>这是最原始，也是众所周知的最慢的算法了。他的名字的由来因为它的工作看来象是冒泡： <br>#include &lt;iostream.h&gt; </p>
<p>void BubbleSort(int* pData,int Count) <br>{ <br>int iTemp; <br>for(int i=1;i&lt;Count;i++) <br>{ <br>for(int j=Count-1;j&gt;=i;j--) <br>{ <br>if(pData[j]&lt;pData[j-1]) <br>{ <br>iTemp = pData[j-1]; <br>pData[j-1] = pData[j]; <br>pData[j] = iTemp; <br>} <br>} <br>} <br>} </p>
<p>void main() <br>{ <br>int data[] = {10,9,8,7,6,5,4}; <br>BubbleSort(data,7); <br>for (int i=0;i&lt;7;i++) <br>cout&lt;&lt;data[i]&lt;&lt;" "; <br>cout&lt;&lt;"\n"; <br>} </p>
<p>倒序(最糟情况) <br>第一轮：10,9,8,7-&gt;10,9,7,8-&gt;10,7,9,8-&gt;7,10,9,8(交换3次) <br>第二轮：7,10,9,8-&gt;7,10,8,9-&gt;7,8,10,9(交换2次) <br>第一轮：7,8,10,9-&gt;7,8,9,10(交换1次) <br>循环次数：6次 <br>交换次数：6次 </p>
<p>其他： <br>第一轮：8,10,7,9-&gt;8,10,7,9-&gt;8,7,10,9-&gt;7,8,10,9(交换2次) <br>第二轮：7,8,10,9-&gt;7,8,10,9-&gt;7,8,10,9(交换0次) <br>第一轮：7,8,10,9-&gt;7,8,9,10(交换1次) <br>循环次数：6次 <br>交换次数：3次 </p>
<p>上面我们给出了程序段，现在我们分析它：这里，影响我们算法性能的主要部分是循环和交换， <br>显然，次数越多，性能就越差。从上面的程序我们可以看出循环的次数是固定的，为1+2+...+n-1。 <br>写成公式就是1/2*(n-1)*n。 <br>现在注意，我们给出O方法的定义： </p>
<p>若存在一常量K和起点n0，使当n&gt;=n0时，有f(n)&lt;=K*g(n),则f(n) = O(g(n))。（呵呵，不要说没 <br>学好数学呀，对于编程数学是非常重要的！！！） </p>
<p>现在我们来看1/2*(n-1)*n，当K=1/2，n0=1，g(n)=n*n时，1/2*(n-1)*n&lt;=1/2*n*n=K*g(n)。所以f(n) <br>=O(g(n))=O(n*n)。所以我们程序循环的复杂度为O(n*n)。 <br>再看交换。从程序后面所跟的表可以看到，两种情况的循环相同，交换不同。其实交换本身同数据源的 <br>有序程度有极大的关系，当数据处于倒序的情况时，交换次数同循环一样（每次循环判断都会交换）， <br>复杂度为O(n*n)。当数据为正序，将不会有交换。复杂度为O(0)。乱序时处于中间状态。正是由于这样的 <br>原因，我们通常都是通过循环次数来对比算法。 </p>
<p><br>2.交换法： <br>交换法的程序最清晰简单，每次用当前的元素一一的同其后的元素比较并交换。 <br>#include &lt;iostream.h&gt; <br>void ExchangeSort(int* pData,int Count) <br>{ <br>int iTemp; <br>for(int i=0;i&lt;Count-1;i++) <br>{ <br>for(int j=i+1;j&lt;Count;j++) <br>{ <br>if(pData[j]&lt;pData[i]) <br>{ <br>iTemp = pData[i]; <br>pData[i] = pData[j]; <br>pData[j] = iTemp; <br>} <br>} <br>} <br>} </p>
<p>void main() <br>{ <br>int data[] = {10,9,8,7,6,5,4}; <br>ExchangeSort(data,7); <br>for (int i=0;i&lt;7;i++) <br>cout&lt;&lt;data[i]&lt;&lt;" "; <br>cout&lt;&lt;"\n"; <br>} <br>倒序(最糟情况) <br>第一轮：10,9,8,7-&gt;9,10,8,7-&gt;8,10,9,7-&gt;7,10,9,8(交换3次) <br>第二轮：7,10,9,8-&gt;7,9,10,8-&gt;7,8,10,9(交换2次) <br>第一轮：7,8,10,9-&gt;7,8,9,10(交换1次) <br>循环次数：6次 <br>交换次数：6次 </p>
<p>其他： <br>第一轮：8,10,7,9-&gt;8,10,7,9-&gt;7,10,8,9-&gt;7,10,8,9(交换1次) <br>第二轮：7,10,8,9-&gt;7,8,10,9-&gt;7,8,10,9(交换1次) <br>第一轮：7,8,10,9-&gt;7,8,9,10(交换1次) <br>循环次数：6次 <br>交换次数：3次 </p>
<p>从运行的表格来看，交换几乎和冒泡一样糟。事实确实如此。循环次数和冒泡一样 <br>也是1/2*(n-1)*n，所以算法的复杂度仍然是O(n*n)。由于我们无法给出所有的情况，所以 <br>只能直接告诉大家他们在交换上面也是一样的糟糕（在某些情况下稍好，在某些情况下稍差）。 </p>
<p>3.选择法： <br>现在我们终于可以看到一点希望：选择法，这种方法提高了一点性能（某些情况下） <br>这种方法类似我们人为的排序习惯：从数据中选择最小的同第一个值交换，在从省下的部分中 <br>选择最小的与第二个交换，这样往复下去。 <br>#include &lt;iostream.h&gt; <br>void SelectSort(int* pData,int Count) <br>{ <br>int iTemp; <br>int iPos; <br>for(int i=0;i&lt;Count-1;i++) <br>{ <br>iTemp = pData[i]; <br>iPos = i; <br>for(int j=i+1;j&lt;Count;j++) <br>{ <br>if(pData[j]&lt;iTemp) <br>{ <br>iTemp = pData[j]; <br>iPos = j; <br>} <br>} <br>pData[iPos] = pData[i]; <br>pData[i] = iTemp; <br>} <br>} </p>
<p>void main() <br>{ <br>int data[] = {10,9,8,7,6,5,4}; <br>SelectSort(data,7); <br>for (int i=0;i&lt;7;i++) <br>cout&lt;&lt;data[i]&lt;&lt;" "; <br>cout&lt;&lt;"\n"; <br>} <br>倒序(最糟情况) <br>第一轮：10,9,8,7-&gt;(iTemp=9)10,9,8,7-&gt;(iTemp=8)10,9,8,7-&gt;(iTemp=7)7,9,8,10(交换1次) <br>第二轮：7,9,8,10-&gt;7,9,8,10(iTemp=8)-&gt;(iTemp=8)7,8,9,10(交换1次) <br>第一轮：7,8,9,10-&gt;(iTemp=9)7,8,9,10(交换0次) <br>循环次数：6次 <br>交换次数：2次 </p>
<p>其他： <br>第一轮：8,10,7,9-&gt;(iTemp=8)8,10,7,9-&gt;(iTemp=7)8,10,7,9-&gt;(iTemp=7)7,10,8,9(交换1次) <br>第二轮：7,10,8,9-&gt;(iTemp=8)7,10,8,9-&gt;(iTemp=8)7,8,10,9(交换1次) <br>第一轮：7,8,10,9-&gt;(iTemp=9)7,8,9,10(交换1次) <br>循环次数：6次 <br>交换次数：3次 <br>遗憾的是算法需要的循环次数依然是1/2*(n-1)*n。所以算法复杂度为O(n*n)。 <br>我们来看他的交换。由于每次外层循环只产生一次交换（只有一个最小值）。所以f(n)&lt;=n <br>所以我们有f(n)=O(n)。所以，在数据较乱的时候，可以减少一定的交换次数。 </p>
<p><br>4.插入法： <br>插入法较为复杂，它的基本工作原理是抽出牌，在前面的牌中寻找相应的位置插入，然后继续下一张 <br>#include &lt;iostream.h&gt; <br>void InsertSort(int* pData,int Count) <br>{ <br>int iTemp; <br>int iPos; <br>for(int i=1;i&lt;Count;i++) <br>{ <br>iTemp = pData[i]; <br>iPos = i-1; <br>while((iPos&gt;=0) &amp;&amp; (iTemp&lt;pData[iPos])) <br>{ <br>pData[iPos+1] = pData[iPos]; <br>iPos--; <br>} <br>pData[iPos+1] = iTemp; <br>} <br>} </p>
<p>void main() <br>{ <br>int data[] = {10,9,8,7,6,5,4}; <br>InsertSort(data,7); <br>for (int i=0;i&lt;7;i++) <br>cout&lt;&lt;data[i]&lt;&lt;" "; <br>cout&lt;&lt;"\n"; <br>} </p>
<p>倒序(最糟情况) <br>第一轮：10,9,8,7-&gt;9,10,8,7(交换1次)(循环1次) <br>第二轮：9,10,8,7-&gt;8,9,10,7(交换1次)(循环2次) <br>第一轮：8,9,10,7-&gt;7,8,9,10(交换1次)(循环3次) <br>循环次数：6次 <br>交换次数：3次 </p>
<p>其他： <br>第一轮：8,10,7,9-&gt;8,10,7,9(交换0次)(循环1次) <br>第二轮：8,10,7,9-&gt;7,8,10,9(交换1次)(循环2次) <br>第一轮：7,8,10,9-&gt;7,8,9,10(交换1次)(循环1次) <br>循环次数：4次 <br>交换次数：2次 <br>&lt; <br>本文来自: 站长(<a href="http://www.qqcf.com/">http://www.qqcf.com</a>) 详细出处参考：<a href="http://study.qqcf.com/web/202/22561.htm">http://study.qqcf.com/web/202/22561.htm</a></p>
<img src ="http://www.cppblog.com/fdsajhg/aggbug/123442.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fdsajhg/" target="_blank">傅先生</a> 2010-08-14 17:16 <a href="http://www.cppblog.com/fdsajhg/archive/2010/08/14/123442.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++下对冒泡排序算法的改进</title><link>http://www.cppblog.com/fdsajhg/archive/2010/08/14/123440.html</link><dc:creator>傅先生</dc:creator><author>傅先生</author><pubDate>Sat, 14 Aug 2010 09:01:00 GMT</pubDate><guid>http://www.cppblog.com/fdsajhg/archive/2010/08/14/123440.html</guid><wfw:comment>http://www.cppblog.com/fdsajhg/comments/123440.html</wfw:comment><comments>http://www.cppblog.com/fdsajhg/archive/2010/08/14/123440.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fdsajhg/comments/commentRss/123440.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fdsajhg/services/trackbacks/123440.html</trackback:ping><description><![CDATA[<p>摘 要：本文对排序中最常见的起泡法进行分析，发现在实现单向起泡的同时可以实现双向起泡，从而实现了冒泡算法的改进，提高了运算速度。</p>
<p>　　关键字：程序设计、起泡、双向起泡、VC++</p>
<p>　　排序是在程序设计中常碰到的问题，排序算法也有很多种。起泡法是众所周知的排序算法，其原理是每次将相邻两个数进行比较，较大的下沉。其的主程序段如下（用VC++实现）：</p>
<p>Void Bubble Sort (int* pData,int Count) <br>{ <br>　Int iTemp; <br>　for(int i=1;i&lt;Count;i++) <br>　{<br>　　For (int j=Count-1;j&gt;=i;j--) <br>　　{<br>　　　if(pData[j]&lt;pData[j-1]) <br>　　　{<br>　　　　iTemp = pData[j-1]; <br>　　　　pData[j-1] = pData[j]; <br>　　　　pData[j] = iTemp; <br>　　　} <br>　　}<br>　}<br>} </p>
<p>　　我们分析上述程序段可以发现起泡法是从一端开始比较的，第一次循环就是把最小数上升到第一位置，第二次循环就是把第二最小数上升到第二位置。如此循环实现数据的排序。那么我们是否可以找到最小数的同时找到最大数呢？当然可以。方法是在一端起泡时同时在另一端也进行起泡。即反向起泡。下面的程序段实现的是双向起泡：</p>
<p>void Bubble2Sort(int* pData,int Count) <br>{<br>　int iTemp; <br>　int left = 1; <br>　int right =Count -1; <br>　int t; <br>　do <br>　{<br>　　//正向的部分 <br>　　for(int i=right;i&gt;=left;i--) <br>　　{<br>　　　if(pData[i]&lt;pData[i-1]) <br>　　　{<br>　　　　iTemp = pData[i]; <br>　　　　pData[i] = pData[i-1]; <br>　　　　pData[i-1] = iTemp; <br>　　　　t = i; <br>　　　} <br>　　} <br>　　left = t+1; <br>　　//反向的部分 <br>　　for(i=left;i&lt;right+1;i++) <br>　　{<br>　　　if(pData[i]&lt;pData[i-1]) <br>　　　{<br>　　　　iTemp = pData[i]; <br>　　　　pData[i] = pData[i-1]; <br>　　　　pData[i-1] = iTemp; <br>　　　　t = i; <br>　　　}<br>　　}<br>　　right = t-1; <br>　}while(left&lt;=right); <br>} </p>
<p>　　分析上面的程序段我们可以发现正向起泡时第一次循环找出了最小数，反向起泡第一次循环找到最大数。很显然在一次循环中即可以找到一个最小的数还可以找到一个最大的数，所以用双向冒泡排序的交换的次数减少了，从而达到了优化起泡法的作用。 <br>文章出处：飞诺网(<a href="http://www.firnow.com):http://dev.firnow.com/course/3_program/vc/vc_js/20100805/526159.html">www.firnow.com):http://dev.firnow.com/course/3_program/vc/vc_js/20100805/526159.html</a></p>
<img src ="http://www.cppblog.com/fdsajhg/aggbug/123440.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fdsajhg/" target="_blank">傅先生</a> 2010-08-14 17:01 <a href="http://www.cppblog.com/fdsajhg/archive/2010/08/14/123440.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>