经典c编程实例.pdf
《经典c编程实例.pdf》由会员分享,可在线阅读,更多相关《经典c编程实例.pdf(54页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、1.冒泡法:这是最原始,也是众所周知的最慢的算法了。他的名字的由来因为它的工作看来象是冒泡:Si n c l u d e v o i d Bu b b l e So r t(i n t*p Da t a,i n t Co u n t)(i n t i Te m p;f o r(i n t i=l;i=i;j一)(i f(p Da t a j p Da t a j-l )(i Te m p =p Da t a j-1;p Da t a j-l =p Da t a j ;p Da t a j =i Te m p;)v o i d m a i n 0(i n t d a t a =10,9,8,7,
2、6,5,4;Bu b b l e So r t(d a t a,7);f o r (i n t i=0;i 7;i+)c o u t d a t a i z/c o u t 10,9,7,8-10,7,9,8-7,10,9,8(交换 3 次)第 二 轮:7,10,9,8-7,10,8,9-7,8,10,9(交换 2 次)第一轮:7,8,10,9-7,8,9,10(交换 1 次)循环次数:6次交换次数:6次其他:第 一 轮:8,10,7,9-8,10,7,9-8,7,10,9-7,8,10,9(交换 2 次)第二轮:7,8,10,9-7,8,10,9-7,8,10,9(交换 0 次)第 一 轮:
3、7,8,10,9-7,8,9,10(交换 1 次)循环次数:6次交换次数:3次上面我们给出了程序段,现在我们分析它:这里,影响我们算法性能的主要部分是循环和交换,显然,次数越多,性能就越差。从上面的程序我们可以看出循环的次数是固定的,为1+2+.+n-l o写成公式就是l/2*(n-l)*n。现在注意,我们给出0方法的定义:若存在一常量K和起点n 0,使当n=n 0时,有f (n)v o i d Ex c h a n g e So r t(i n t*p Da t a,i n t Co u n t)(i n t i Te m p;f o r(i n t i=0;i Co u n t-l;i+)
4、(f o r (i n t j=i+l;j Co u n t;j+)(i f(p Da t a j p Da t a i )(i Te m p =p Da t a i ;p Da t a i =p Da t a j ;p Da t a j =i Te m p;)v o i d m a i n ()i n t d a t a =10,9,8,7,6,5,4;ExchangeSort(data,7);for(int i=0;i9,10,8,7-8,10,9,7-7,10,9,8(交换 3 次)第二轮:7,10,9,8-7,9,10,8-7,8,10,9(交换 2 次)第 一 轮:7,8,10,9-
5、7,8,9,10(交换 1 次)循环次数:6 次交换次数:6 次其他:第 一 轮:8,10,7,9-8,10,7,9-7,10,8,9-7,10,8,9(交换 1 次)第二轮:7,10,8,9-7,8,10,9-7,8,10,9(交换 1 次)第 一 轮:7,8,10,9-7,8,9,10(交换 1 次)循环次数:6 次交换次数:3 次从运行的表格来看,交换几乎和冒泡一样糟。事实确实如此。循环次数和冒泡一样也是l/2*(n T)*n,所以算法的复杂度仍然是0(n*n)。由于我们无法给出所有的情况,所以只能直接告诉大家他们在交换上面也是一样的糟糕(在某些情况下稍好,在某些情况下稍差)。3.选择法
6、:现在我们终于可以看到 点希望:选择法,这种方法提高了一点性能(某些情况下)这种方法类似我们人为的排序习惯:从数据中选择最小的同第一个值交换,在从省下的部分中选择最小的与第二个交换,这样往复下去。include void SelectSort(int*pData,int Count)(int iTemp;int iPos;fo r(int i=0;iCount-l;i+)(iTemp=pD atai;iPos=i;for(int j=i+l;jCount;j+)if(pD a ta j iT e mp)(iT e mp=pD a ta j;iP os=j;)pD a ta iP os =pD
7、a ta i;pD a ta i =iT e mp;)void ma in()(int d a ta =1 0,9,8,7,6,5,4;S e le c tS ort(d a ta,7);f or(int i=0;i 7;i+)c out d a ta i,/;c out n;该排序法的图示如下;i=0 时:iT e mp=pD a ta 0 =1 0;iP os=i=0;j=l;pD a ta j pD a ta l=9 1 0;iT e mp=pD a ta 1 =9;ipos=j=l;j+=2j=2;pD a ta j pD a ta 2 =8 9;i T e mp=pD a ta 2
8、=8;ipos=j=2;j+=3j=6;pD a ta j pD a ta 6 =4 (iT e mp=9)1 0,9,8,7-(iT e mp=8)1 0,9,8,7-(iT e mp=7)7,9,8,1 0 (交换 1次)第二轮:7,9,8,1 0-7,9,8,1 0(iT e mp=8)-(iT e mp=8)7,8,9,1 0(交换 1 次)第 一 轮:7,8,9,1 0-(iT e mp=9)7,8,9,1 0 (交换 0 次)循环次数:6次交换次数:2次其他:第一轮:8,1 0,7,9-(iT e mp=8)8,1 0,7,9-(iT e mp=7)8,1 0,7,9-(iT e
9、mp=7)7,1 0,8,9(交换 1次)第二轮:7,1 0,8,9-(iT e mp=8)7,1 0,8,9-(iT e mp=8)7,8,1 0,9 (交换 1 次)第 一 轮:7,8,1 0,9-(iT e mp=9)7,8,9,1 0 (交换 1 次)循环次数:6次交换次数:3次遗憾的是算法需要的循环次数依然是l/2*(n-l)*n。所以算法复杂度为0(n*n)。我们来看他的交换。由于每次外层循环只产生一次交换(只有一个最小值)。所 以 f(n)=n所以我们有f(n)=0(n)。所以,在数据较乱的时候,可以减少一定的交换次数。4.插入法:插入法较为复杂,它的基本工作原理是抽出牌,在前面
10、的牌中寻找相应的位置插入,然后继续下一张#inc lud e void I nse rtS ort(int*pD a ta,int C ount)(int iT e mp;int iP os;f or(int i=l;i=0)&(iT e mp pD a ta iP os)(pD a ta iP os+l =pD a ta iP os;iP os一;pD a ta iP os+l =iT e mp;void ma inO(int d a ta =1 0,9,8,7,6,5,4;I nse rtS ort(d a ta,7);f or(int i=0;i 7;i+)c out =0&iT e m
11、p=9 =0&iT e mp=8 pD a ta 1 =1 0;pD a ta 2 =pD a ta l=1 0;ipos=1-1=0;9-1 0-1 0-7-6-5-4ipos=0 =0&i T e mp=8 =0&i T e mp=7 =0&i T e mp=8 =0&i T e mp=7 =0&i T e mp=6 =0&i T e mp=7 =0&i T e mp=7 =0&i T e mp=7 9,1 0,8,7 (交换 1 次)(循环 1 次)第 二 轮:9,1 0,8,7-8,9,1 0,7(交换 1 次)(循环 2 次)第一轮:8,9,1 0,7-7,8,9,1 0(交换 1
12、次)(循环 3 次)循环次数:6次交换次数:3次其他:第一轮:8,1 0,7,9-8,1 0,7,9(交换 0 次)(循环 1 次)第二轮:8,1 0,7,9-7,8,二,9(交换 1 次)(循环 2 次)第一轮:7,8,1 0,9-7,8,9,1 0(交换 1 次)(循环 1 次)循环次数:4次交换次数:2次上面结尾的行为分析事实上造成了一种假象,让我们认为这种算法是简单算法中最好的,其实不是,因为其循环次数虽然并不固定,我们仍可以使用0方法。从上面的结果可以看出,循环的次数f(n)=l/2*n*(n-l)=l/2*n*n。所以其复杂度仍为0(n*n)(这里说明一下,其实如果不是为了展示这些
13、简单排序的不同,交换次数仍然可以这样推导)。现在看交换,从外观上看,交换次数是0(n)(推导类似选择法),但我们每次要进行与内层循环相同次数的操作。正常的一次交换我们需要三次而这里显然多了一些,所以我们浪费了时间。最终,我个人认为,在简单排序算法中,选择法是最好的。插入排序#i n c l u d e u s i n g n a me s p a c e s t d;v o i d c o u t s t r e a m(i n t a ,i n t n)f o r(i n t i=0;i!=n;i+)v o i d i n s e r t s o r t(i n t a ,i n t n)i
14、 n t t e mp;f o r(i n t i=l;i O&t e mp a j-l )(a j =a j-l ;J ;)a j =t e mp;)i n t ma i n()(i n t a 5 =l,6,4,8,4);i n s e r t s o r t (a,5);插入排序c o u t s t r e a m(a,5);/r e t u r n 0;)二、高级排序算法:高级排序算法中我们将只介绍这一种,同时也是目前我所知道(我看过的资料中)的最快的。它的工作看起来仍然象一个二叉树。首先我们选择一个中间值mi d d l e 程序中我们使用数组中间值,然后把比它小的放在左边,大的放
15、在右边(具体的实现是从两边找,找到一对后交换)。然后对两边分别使用这个过程(最容易的方法一递归)。1.快速排序:#in cl u de v o id r u n(in t*p D at a,in t l eft,in t r ight)in t i,j;in t m iddl e,iT em p;i=l eft;J =r ight;m iddl e=p D at a(l eft+r ight)/2;求中间值do w hi 1 e(p D at a im idd 1 e)&(i m iddl e)&(j l eft)从右扫描大于中值的数j;if(iC j)找到了一对值(交换iT em p =p
16、D at a i;p D at a i=p D at aEj;p D at a j=iT em p;i+;j;)w hil e(i=j);如果两边扫描的下标交错,就停止(完成一次)当左边部分有值(l eft j),递归左半边if(l eft i)r u n(p D at a,i,r ight);)v o id Q u ick s o r t(in t*p D at a,in t C o u n t)(r u n (p D at a,0,C o u n t-1);)v o id m ain()(in t dat a =10,9,8,7,6,5,4 ;Q u ick s o r t(dat a,7
17、);fo r (in t i=0;i7;i+)co u t dat a i/zco u t,z n,z;这里我没有给出行为的分析,因为这个很简单,我们直接来分析算法:首先我们考虑最理想的情况1.数组的大小是2的幕,这样分下去始终可以被2整除。假设为2的 k次方,即 k=l o g2(n)。2 .每次我们选择的值刚好是中间值,这样,数组才可以被等分。第一层递归,循环n 次,第二层循环2*(n/2).所以共有 n+2 (n/2)+4 (n/4)+.+n*(n/n)=n+n+n+.+n=k*n=l o g2 (n)*n所以算法复杂度为0(l o g2(n)*n)其他的情况只会比这种情况差,最差的情况
18、是每次选择到的m iddl e都是最小值或最大值,那么他将变成交换法(由于使用了递归,情况更糟)。但是你认为这种情况发生的几率有多大?呵呵,你完全不必担心这个问题。实践证明,大多数的情况,快速排序总是最好的。如果你担心这个问题,你可以使用堆排序,这 是 种 稳 定 的 0(l o g2(n)*n)算法,但是通常情况下速度要慢于快速排序(因为要重组堆)。三、其他排序1.双向冒泡:通常的冒泡是单向的,而这里是双向的,也就是说还要进行反向的工作。代码看起来复杂,仔细理一下就明白了,是一个来回震荡的方式。写这段代码的作者认为这样可以在冒泡的基础上减少一些交换(我不这么认为,也许我错了)。反正我认为这是
19、一段有趣的代码,值得一看。i ncl ude vo i d B ubbl e2So r t(i nt*p D ata,i nt C o unt)i nt i Tem p;i nt l eft=1;i nt r i g h t=C o unt-1;i nt t;do(正向的部分fo r(i nt i=r i g h t;i=l eft;i-)(i f(p D ata i p D at a i-1)(i Tem p =p D ata i;p D ata i=p D ata i-l;p D ata i-l =i Tem p;t=i;)l eft=t+1;反向的部分fo r (i=l eft;i r
20、i g h t+l;i+)i f(p D ata i p D ata i-1)i Tem p =p D ata i;p D ata i =p D ata i-l;p D ata i l =i Tem p;t=i;)r i g h t=t-1;wh i l e(l eft=r i g h t);)vo i d m ai n()(i nt data =10,9,8,7,6,5,4;B ubbl e2So r t(data,7);fo r (i nt i=0;i 7;i+)co utdata i/z;co ut n;快速排序#i ncl ude us i ng nam es p ace s td;c
21、l as s Qui ck s o r t(p ubl i c:vo i d q ui ck _s o r t(i nt*x,i nt l o w,i nt h i g h)(i nt p i vo tk ey;i f(l o w h i g h)(p i vo tk ey=p ar ti o n(x,l o w,h i g h);q ui ck _s o r t(x,l o w,p i vo tk ey-1);q ui ck _s o r t(x,p i vo tk ey+1,h i g h);)i nt p ar ti o n(i nt*x,i nt l o w,i nt h i g h)
22、(i nt p i vo tk ey;p i vo tk ey=x l o w;wh i l e(l o w h i g h)(wh i 1e(l o w=p i vo tk ey)h i g h;还有wh i l e循环只执行这一句x l o w=x h i g h;wh i l e(l o w h i g h&x l o w=p i vo tk ey)+l o w;还有wh i l e循环只执行这一句x h i g h=x l o w;)x l o w=p i vo tk ey;r etur n l o w;);i nt m ai n()(i nt x 10=52,49,80,36,14,
23、58,61,97,23,65;Qui ck s o r t q s;q s.q ui ck s o r t(x,0,9);co ut 排好序的数字序列为:“endl;fo r (i nt i=0;i 10;i+)(p r i ntf(%d,x i);)r etur n 0;)2.SHELL 排序这个排序非常复杂,看了程序就知道了。首先需要一个递减的步长,这里我们使用的是9、5、3、1(最后的步长必须是1)。工作原理是首先对相隔9-1个元素的所有内容排序,然后再使用同样的方法对相隔5-1个元素的排序以次类推。#i ncl ude vo i d Sh el l So r t(i nt*p D at
24、a,i nt C o unt)(i nt s tep 4;s tep 0=9;s tep l =5;s tep 2=3;s tep 3=1;i nt i Tem p;i nt k,s,w;fo r(i nt i=0;i 4;i+)(k =s tep i;s =-k;fo r (i nt j=k;j C o unt;j+)(i Tem p =p D ata j;w=j-k;求上s tep 个元素的下标i f(s =0)s =-k;s+;p D ata s =i Tem p;)wh i l e(i Tem p=0)&(w=C o unt)(p D ata w+k =p D ata w;w=w-k;
25、)p D ata w+k =i Tem p;)vo i d m ai n()(i nt data =10,9,8,7,6,5,4,3,2,1,-10,-1;Sh el l So r t(data,12);fo r (i nt i=0;i 12;i+)co utdata i z,co ut“n;)呵呵,程序看起来有些头疼。不过也不是很难,把 s=0的块去掉就轻松多了,这里是避免使用0 步长造成程序异常而写的代码。这个代码我认为很值得一看。这个算法的得名是因为其发明者的名字D.L.SHELL。依照参考资料上的说法:”由于复杂的数学原因避免使用2 的基次步长,它能降低算法效率 另外算法的复杂度为n
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 经典 编程 实例
限制150内