排序算法的比较、选择及其改进
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
排序算法的比较、选择及其改进
[摘要]排序是计算机科学中最重要的研究问题之一。
在对常用的几种排序算法进行了综合比较的基础上,本文提出了在实际应用中如何选择排序算法的一般原则,同时也给出了一些算法的改进策略及其C语言实现。
[关键词]排序改进比较选择算法
一、引言
排序是计算机科学中最重要的研究问题之一, 它在计算机图形、计算机辅助设计、机器人、模式识别及统计学等领域具有广泛的应用。
由于它固有的理论上的重要性,2000年它被列为对科学和工程计算的研究与实践影响最大的10大问题之一。
其功能是将一个数据元素的任意序列重新排列成一个按关键字有序的序列。
二、排序算法的性能比较
内部排序算法种类繁多,但就其排序时所遵循的原则而言,大致可分为五大类:插入排序、交换排序、选择排序、归并排序和基数排序。
算法性能的比较主要是从时间复杂度、空间复杂度和稳定性三个方面来综合考虑。
(一)时间复杂度
从平均性能上看,直接插入排序、简单选择排序、冒泡排序这三种“简单排序”为第一类,其时间复杂度均为O(n2);堆排序、归并排序、快速排序属于第二类,其时间复杂度均为O(nlog2n);基数排序则属于第三类,其时间复杂度为O(d(n+rd)),也可以写为O(dn),因此最适用于n值很大而关键字较小的序列。
当原表有序或基本有序时,直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n2);原表是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大。
(二)空间复杂度
从空间复杂度来看,归并排序最大,对n 个记录需要附加等量的存储量,其空间复杂度为O(n);基数排序次之,它需要附加较多存储空间用于存储队列指针和用作结点指针域,空间复杂度为O(rd);快速排序单独讨论,其递归算法需要使用堆栈来实现,栈中存放待排序记录序列的首尾位置,在一般情况下需要栈空间O(nlog2n),最坏情况下,所需要的栈空间为O(n);其余排序算法
的空间复杂度最小,仅为O(1)。
(三)稳定性
从算法的稳定性而言,所有排序算法可分为两类:直接插入排序、简单选择排序、冒泡排序、归并排序和基数排序为第一类,均属于稳定的算法,而快速排序和堆排序则属于第二类,是不稳定算法。
三、排序算法的选择
根据以上的性能比较,我们发现每种排序算法都各有优缺点。
因此,在实用时需根据不同情况适当选用,甚至可以将多种方法结合起来使用。
(一)选择排序算法的依据
影响排序的因素有很多,平均时间复杂度低的算法并不一定就是最优的。
相反,有时平均时间复杂度高的算法可能更适合某些特殊情况。
同时,选择算法时还得考虑它的可读性,以利于软件的维护。
一般而言,需要考虑的因素有以下四点:
1.待排序的记录数目n的大小;
2.记录本身数据量的大小,也就是记录中除关键字外的其他信息量的大小;
3.关键字的结构及其分布情况;
4.对排序稳定性的要求。
(二)选择排序算法的结论
依据上述在选择排序算法时需考虑的因素,可以得出以下几个结论:
1.数据量不大时选用插入或选择排序,一般不使用或不直接使用传统的冒泡排序;
2.当数据量大而又注重空间复杂性时选择快速排序或堆排序等;
3.在已排序数据上增加若干新数据时,建议使用插入排序;
4.当数据量大而又允许使用较多附加空间时可选择桶排序。
四、一些排序算法的改进策略
常用的排序算法中,有不少是可以根据实际情况而进一步改进完善的,以充
分提高算法的效率。
(一)简单选择排序的改进二元选择排序
传统的简单选择排序,每趟循环只能确定一个元素排序后的定位。
我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。
改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。
具体实现如下:
void SelectSort(RecType r[ ],int n) {
/* 本文中RecType为记录类型,下同*/
int i ,j , min ,max;
for (i=1 ;i r[max].key)
{ max = j ; continue ; }
if (r[j].key 1) {
pos= 0; /*每趟开始时, 无记录交换*/
for (j= 1; j r[j+1].key) {
pos= j; /*记录交换的位置*/
r[0]= r[j];r[j]=r[j+1];r[j+1]=r[0];
} /* end of if */
i= pos; /*为下一趟排序作准备*/
} /* end of while */
}/* end of Bubble_1 */
2.传统冒泡排序中每一趟排序操作只能找一个最大值或最小值,我们考虑利用在每趟排序中进行正向和反向两遍冒泡的方法一次可得到两个最终值(最大者和最小者) , 从而使排序趟数几乎减少了一半。
改进后的算法实现为:
void Bubble_2 ( RecType r[ ], int n){
low = 1; high= n; /*置变量的初始值*/ while (low < high) {
for ( j= low; j< high; j+ + )
/*正向冒泡, 找到最大者*/。