各种排序算法效率分析
(2011-02-01 05:36:51)
标签:
排序算法效率分析数据结构 |
分类: 学习 |
The Efficiency Analysis of Various Sort Programs
ika_酱 2010-03
南中国第一产业大学 信息学院软件工程系
【摘要】排序算法是计算机算法运算中最重要的,一个好的排序不仅可以使信息查找的效率提高,而且直接影响计算机的工作效率。本文通过对几种常用排序算法的讨论,并予以编程实现,采取对数据的测试与比较,验证算法的优越。
【关键词】排序;算法;效率;分析
[Abstract]Sorting algorithm is the most important part of computer programing. An excellent sort not only can improve the efficiency of searching information, but also directly influences computer’s working efficiency. In this article, several sorting algorithm commonly used would be discussed.
[Key words] sort, algorithm, efficiency, analysis
在日常生活中经常需要对所收集到的各种数据信息进行处理, 这些数据处理中经常用的核心运算就是排序。例如图书馆理员将书籍按照编号排序放置在书架上, 方便读者查找; 打开计算机的资源管理器, 可以选择不同类型来排列图标等等。排序已经广泛应用在几乎所有领域。在当今的计算机系统中, 花费在排序上的时间占系统CPU 运行时间的比重很大。
1 概述
1.1 排序的基本概念
排序(本文提及的排序均为内部排序)是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个按关键字有序的序列。
排序的确切定义如下:
假设含n个记录的序列为
{R1,R2,……,Rn}
其相应的关键字序列为
{K1,K2,……,Kn}
需确定1,2,…,n的一种排列p1,p2,…,pn,使其相应的关键字满足如下的非递减(或非递增)关系
Kp1 ≤ Kp2 ≤ …… ≤ Kpn
即使n个记录的序列成为一个按关键字有序的序列
{Rp1,Rp2,……,Rpn}
这样一种操作称为排序。
内部排序的方法很多,但就其全面性能而言,很难提出一种被认为是最好的方法,每一种方法都有各自的优缺点,适合在不同的环境(如记录的初始排列状态等)下使用。如果排序过程中依据的不同原则对内部排序方法进行分类,则大致可分为插入排序、交换排序、选择排序、归并排序和计数排序等五类;如果按内部排序过程中所需的工作量来区分,则可分为3类:(1)简单的排序方法,其时间复杂度为O(n2);(2)先进的排序方法,其时间复杂度为O(n log n);(3)基数排序,其时间复杂度为O(d·n)。
1.2 排序基本操作
通常,在排序的过程中需进行下列两种基本操作:
(1)比较两个关键字的大小;
(2)讲记录从一个位置移动至另一个位置。
前一个操作对大多数排序方法来说都是必须的,而后一个操作可以通过改变记录的存储方式来予以避免。
1.3 数据元素常用的存储方式
(1)顺序存储,以顺序表作为存储结构;
(2)链式存储,以链表作为存储结构;
(3)索引存储,用顺序的方式存储待排序的记录,但同时建立一个索引表。
1.4 排序算法性能评价
(1)时间复杂度;
(2)空间复杂度;
(3)执行时间开销。
要全面分析一个算法,应该考虑它在最好情况下的代价(正序)、最坏情况下的代价(逆序)和平均情况下的代价。
2 算法描述
2.1 直接插入排序
直接插入排序(Straight Insertion Sort)是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。它的基本思想是,将待排序的记录集分成两部分,第一部分已排好序,第二部分未排好序。排序中,每次都是从第二部分中取出一条记录,将其插入到第一部分,并使其保持有序。初始时,任取一条记录作为第一部分,而其他记录作为第二部分。显然,随着排序过程的进行,第一部分不断扩大,第二部分不断缩小。总有一次,第二部分变为空,而第一部分包含所有记录并且是有序的。
从空间来看,直接插入排序只需要一个记录的辅助空间;从时间来看排序的基本操作为:比较两个关键字的大小和移动记录。该算法是稳定的,且时间复杂度为O(n2)。
2.2 希尔排序
2.3冒泡排序
冒泡排序(Bubble Sort)是一个最简单的交换排序方法,它和气泡从水中往上冒的情况有些类似。具体做法是:先将第一个记录的键值和第二个记录的键值比较,如a[0]>a[1],则将二者记录交换,然后比较第二个和第三个记录的键值,以此类推直到第n-1个记录和第n个记录进行比较交换,称为一趟冒泡。一趟冒泡后,键值最大的记录传到了最末尾的位置。重复上述过程,直到有一趟比较之后没有出现记录交换。
2.4 快速排序
快速排序(Quick Sort)是冒泡排序的一种改进。快速排序的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对着两部分记录继续进行排序,以达到整个序列有序。
2.5 简单选择排序
设待排序的记录集中记录的下标(位置)为0~(n-1),则简单选择排序的基本做法是:首先从位置为0~(n-1)的记录中选出键值最小的记录,将它与位置为0的记录交换,然后从位置为1~(n-1)的记录中选出键值最小的记录,将它与位置为1的记录交换……最后从位置为n-2与n-1的记录冲选出最小者,将它与位置为n-2的记录交换。至此,所有的记录都按非递减顺序排列了。
2.6 堆排序
3实验
3.1实验设计
排序算法的时间开销主要是花费在元素的比较和移动这两方面上,可以通过测定各算法在不同规模数据量(10、30、50、100、500、1000、2500、5000)时正序、逆序和随机数的情况下移动次数和比较次数,分析算法的效率。
3.2实验环境
计算机软硬件配置
CPU |
Memory |
Hard Disk |
OS |
Software |
Intel Pentium Dual Core T1600 1.66GHz |
1.00GB |
160GB |
Windows7 |
Visual C++ 6.0; Microsoft Excel 2007 |
3.3实验数据
直接插入排序(Insertion Sort) |
||||||
数据量n/个 |
正序 |
逆序 |
随机数 |
|||
比较/次 |
移动/次 |
比较/次 |
移动/次 |
比较/次 |
移动/次 |
|
10 |
9 |
0 |
54 |
63 |
27 |
32 |
30 |
29 |
0 |
464 |
493 |
254 |
277 |
50 |
49 |
0 |
1274 |
1323 |
717 |
764 |
100 |
99 |
0 |
5049 |
5148 |
2447 |
2534 |
500 |
499 |
0 |
125249 |
125748 |
61840 |
62331 |
1000 |
999 |
0 |
500499 |
501498 |
248292 |
249277 |
2500 |
2499 |
0 |
3126249 |
3128748 |
1545783 |
1548272 |
5000 |
4999 |
0 |
12502499 |
12507498 |
6282175 |
6287158 |
希尔排序(Shell Sort) |
||||||
数据量n/个 |
正序 |
逆序 |
随机数 |
|||
比较/次 |
移动/次 |
比较/次 |
移动/次 |
比较/次 |
移动/次 |
|
10 |
25 |
0 |
62 |
35 |
53 |
26 |
30 |
98 |
0 |
295 |
187 |
264 |
149 |
50 |
208 |
0 |
521 |
311 |
677 |
377 |
100 |
509 |
0 |
1285 |
772 |
1412 |
768 |
500 |
3514 |
0 |
9650 |
5972 |
11029 |
6300 |
1000 |
8015 |
0 |
21787 |
13444 |
27706 |
15865 |
2500 |
25061 |
0 |
64304 |
39156 |
92319 |
51668 |
5000 |
55017 |
0 |
141093 |
85812 |
209185 |
116420 |
冒泡排序(Bubble Sort) |
||||||
数据量n/个 |
正序 |
逆序 |
随机数 |
|||
比较/次 |
移动/次 |
比较/次 |
移动/次 |
比较/次 |
移动/次 |
|
10 |
9 |
0 |
90 |
135 |
70 |
75 |
30 |
29 |
0 |
870 |
1305 |
673 |
717 |
50 |
49 |
0 |
2450 |
3675 |
1912 |
2106 |
100 |
99 |
0 |
9900 |
14850 |
7246 |
6972 |
500 |
499 |
0 |
249500 |
374250 |
188859 |
193815 |
1000 |
999 |
0 |
999000 |
1498500 |
750491 |
755313 |
2500 |
2499 |
0 |
6247500 |
9371250 |
4661010 |
4619664 |
5000 |
4999 |
0 |
24995000 |
37492500 |
18658744 |
18497127 |
快速排序(Quick Sort) |
||||||
数据量n/个 |
正序 |
逆序 |
随机数 |
|||
比较/次 |
移动/次 |
比较/次 |
移动/次 |
比较/次 |
移动/次 |
|
10 |
108 |
45 |
108 |
45 |
69 |
36 |
30 |
928 |
145 |
928 |
145 |
334 |
143 |
50 |
2548 |
245 |
2548 |
245 |
637 |
224 |
100 |
10098 |
495 |
10098 |
495 |
1652 |
543 |
500 |
40198 |
995 |
40198 |
995 |
11679 |
3134 |
1000 |
1000998 |
4995 |
1000998 |
4995 |
25938 |
6732 |
2500 |
6252498 |
12495 |
6252498 |
12495 |
73943 |
18387 |
5000 |
25004998 |
24995 |
25004998 |
24995 |
171960 |
38983 |
简单选择排序(Selection Sort) |
||||||
数据量n/个 |
正序 |
逆序 |
随机数 |
|||
比较/次 |
移动/次 |
比较/次 |
移动/次 |
比较/次 |
移动/次 |
|
10 |
63 |
0 |
93 |
40 |
81 |
32 |
30 |
493 |
0 |
733 |
270 |
582 |
141 |
50 |
1323 |
0 |
1973 |
700 |
1529 |
296 |
100 |
5148 |
0 |
7698 |
2650 |
5568 |
614 |
500 |
125748 |
0 |
188498 |
63250 |
128592 |
3838 |
1000 |
501498 |
0 |
751998 |
251500 |
507860 |
8342 |
2500 |
3128748 |
0 |
4692498 |
1566250 |
3146833 |
23073 |
5000 |
12507498 |
0 |
18759998 |
6257500 |
12548271 |
50759 |
堆排序(Heap Sort) |
||||||
数据量n/个 |
正序 |
逆序 |
随机数 |
|||
比较/次 |
移动/次 |
比较/次 |
移动/次 |
比较/次 |
移动/次 |
|
10 |
46 |
44 |
38 |
35 |
44 |
39 |
30 |
216 |
180 |
196 |
151 |
208 |
164 |
50 |
444 |
344 |
386 |
281 |
422 |
313 |
100 |
1094 |
789 |
956 |
665 |
1052 |
737 |
500 |
7792 |
5103 |
7028 |
4425 |
7444 |
4798 |
1000 |
17626 |
11207 |
15982 |
9815 |
16888 |
10576 |
2500 |
51070 |
31563 |
46728 |
27979 |
48806 |
29798 |
5000 |
112186 |
68431 |
103264 |
60935 |
107726 |
64599 |
4效率分析
4.1图表分析
4.1.1正序
分析图4-1和4-2,直接插入排序、冒泡排序、希尔排序和简单选择排序等相对简单容易实现的算法的移动次数均为0,而堆排序和快速排序则仍需要对元素进行移动的操作;在比较次数方面直接插入排序和冒泡排序远远优于其他排序。
整体来说在最好情况下,直接插入排序和冒泡排序实现时的效率是最高的。
4.1.2逆序
分析图4-3和4-4,直接插入排序、冒泡排序和简单选择排序等在正序情况中表现优越的算法此时的表现却是差强人意,特别当数据量比较大的时候,无论是比较次数还是移动次数都远远超过堆排序、希尔排序和快速排序等。
整体来说在最坏情况下,堆排序和快速排序展现出非常高的效率。
4.1.3随机数
分析图4-5和4-6,当数据量很大时,冒泡排序和简单选择排序的效率是最差的,堆排序的效率最好,快速排序次之。
整体来说一般情况下,堆排序和快速排序的效率都很高。
4.2算法时间复杂度
衡量一个算法的时间度量是用时间复杂度来衡量,表示为:
T ( n) = O( f ( n) )
“O”的形式定义为:若f (n) 是正整数n 的一个函数,则xn = O(f (n) ) 表示存在一个正的常数M ,使得当n ≥n0 时都满足xn ≤M f (n) 。
排序方法 |
平均时间复杂度 |
辅助空间 |
稳定性 |
直接插入排序 |
O(n2) |
O(1) |
稳定 |
希尔排序 |
O(n1.3) |
O(1) |
不稳定 |
冒泡排序 |
O(n2) |
O(1) |
稳定 |
快速排序 |
O(n log2 n) |
O(log2 n) |
不稳定 |
简单选择排序 |
O(n2) |
O(1) |
不稳定 |
堆排序 |
O(n log2 n) |
O(1) |
不稳定 |
由上表平均时间复杂度可知,希尔排序、快速排序和堆排序的速度较快。一般情况下,从算法结构的复杂性看,速度慢的排序算法结构都比较简单、直接。希尔排序、快速排序和堆排序均可视为对某一种排序方法的改进,算法结构一般都较为复杂。进一步分析,有:
①
②
③
④
5 小结
排序算法的性能分析和选择是一个复杂而又实际的问题,由上述分析可知,各种排序算法各有优缺点,很难举出一个在各方面都是最优的一个算法。本文只是对六种常见的排序算法进行简单的初级的讨论分析,待排序的数据的规模和数据初始特性是十分重要的选取合适算法的标准,在实际应用中应根据经验和实际情况合理选择算法,或者将一些算法例如快速排序和插入排序等结合起来综合运用。
6 参考文献
[1]严蔚敏,吴伟民.数据结构(C语言版).北京:清华大学出版社,2007
[2]齐德昱.数据结构与算法.北京:清华大学出版社,2003
[3]张乃孝.算法与数据结构(第2版).北京:高等教育出版社,2009
[4]周慧琴.常用内排序算法的分析与比较.忻州师范学院专科部,2009
[5]方斌,邓丽霞.六种排序算法时间性能的实验分析.郧阳师范高等专科学校学报,2005
[6]白红义.常用内排序算法的分析与比较.宁夏交通学校,2008