[排序算法总结]冒泡排序、简单选择排序
2013-09-04 19:33 庸男勿扰 阅读(663) 评论(0) 编辑 收藏 举报排序是日常生活中最常见的操作,也是算法中最有趣的问题之一,排序问题可以描述为:
输入:n个数<a1,a2,…,an>
输出:输入序列的一个排列(即重新排序)<a1’,a2’,….,an’>,使得a1’<=a2’<=…<=an’。
待排序的数也称为关键字(key)。
本篇文章将列举出常见的排序算法,分别从思想、复杂度、稳定性等方面,总结其优劣和适用情形,并给出源码示例。
要想解决排序问题,最直观也是最简单的做法就是两两比较,每次找出当前最大(最小)的,直至整个排序完成。这种算法有一个比较形象的的名字叫“冒泡法”。
一、冒泡排序(BubbleSort):
思想:
冒泡排序的是第一次通过两两比较,找出a1-an中最大的数,并将其放在an的位置,然后第二次执行同样的操作,找出a1-an-1中最大的数,放在an-1的位置,如此下去,直至待排序集合只剩一个数。
代码:
输入:n个元素的数组A[0…n-1]
输出:按非降序排列的数组A[0…n-1](下同)
1 void BubbleSort(int A[],int length) 2 3 { 4 5 for(int i=1; i<length; i++) 6 7 { 8 9 for(int j=1; j<=length-i; j++) 10 11 { 12 13 if(A[j-1]>A[j]) 14 15 { 16 17 swap(A[j-1],A[j]); 18 19 } 20 21 } 22 23 } 24 25 }
复杂度:
不难看出,排序的基本运算是比较操作,当待排序数组长度为n时,比较操作执行的次数是(n-1)+(n-2)+…+1即n(n-1)/2,故其时间复杂度是O(n2)的。至于空间复杂度,冒泡排序无需申请额外的空间。
稳定性:
由算法过程不难看出,冒泡排序不会打乱相同数的原顺序,因此是稳定的。
改进:
算法的外层循环是扫描次数,内层循环是不停对当前待排序数组进行排序,当执行到某次扫描后,数组可能已经是有序的,但是外层循环还是会继续执行,因此,改进的动机便是,当数组已是有序时,即退出排序。判断是否有序的依据便是是否执行了交换操作。因此,改进后的代码如下:
1 void BubbleSort(int A[],int length) 2 3 { 4 5 bool sorted = false; 6 7 for(int i=1; i<length&&!sorted; i++) 8 9 { sorted = true; 10 11 for(int j=1; j<=length-i; j++) 12 13 { 14 15 if(A[j-1]>A[j]) 16 17 { 18 19 swap(A[j-1],A[j]); 20 21 sorted = false; 22 23 } 24 25 } 26 27 } 28 29 }
二、简单选择排序(SelectionSort):
思想:
简单选择排序是对冒泡排序的一种改进,冒泡排序每次都会执行两两交换,不停“吐泡”,目的就是为了让最大的数,能够到当前的最后位置。这中间执行了很多多余的交换操作。简单选择排序是每次找出当前最大的数,放到数组最后,即第一次执行时,找出a1-an中最大的数放到an的位置,在找出a1-an-1中最大的数,放到an-1的位置,直至待排序集合只剩一个数。
不难看出,以上算法过程是一个归纳的过程,因此选择排序也很容易转换成递归版本的算法。
代码:
非递归版本:
1 //返回最大的那个数的位置 2 3 int SelectMaxKey(int A[],int offset) 4 5 { 6 7 int MAX = INT_MIN; 8 9 int pos=0; 10 11 for(int i=0; i<=offset; i++) 12 13 { 14 15 if(A[i]>MAX){ 16 17 MAX = A[i]; 18 19 pos = i; 20 21 } 22 23 } 24 25 return pos; 26 27 } 28 29 30 31 void SelectionSort(int A[],int length) 32 33 { 34 35 int temp; 36 37 for(int i=1; i<length; i++) 38 39 { 40 41 temp = SelectMaxKey(A,length-i); 42 43 if(temp!=length-i) 44 45 swap(A[temp],A[length-i]); 46 47 } 48 49 }
递归版本:
1 void SelectionSortRec(int A[],int offset,int length) 2 3 { 4 5 int k; 6 7 if(offset<length-1) 8 9 { 10 11 k = offset; 12 13 for(int j=offset+1; j<length; j++) 14 15 { 16 17 if(A[j]<A[k]) k = j; 18 19 } 20 21 if(k!=offset) 22 23 swap(A[k],A[offset]); 24 25 SelectionSortRec(A,offset+1,length); 26 27 } 28 29 }
复杂度:
简单选择排序是对冒泡排序的一种改进,减少的只是交换操作,比较操作并没有减少,因此,其时间复杂度也是O(n2),选择排序同样无需申请额外空间。
稳定性:
当当前排序数组中有两个最大的数时,由于在找最大数时,是使用的if(A[i]>MAX)判断,因此,总会把先遇到的那个最大的数放到数组最后,因此打乱了原来的顺序,从这个角度上看,简单选择排序是不稳定的。当然,如果判断使用if(A[i]>=MAX),那么每次总是找最大的数中的最后一个放到数组最后,此时并没有打乱原顺序,此时又可以说是稳定的。
接下来《排序算法总结》系列将带来插入排序和归并排序讲解。以上如有任何错误或表述不清楚的,欢迎指出。
出处:http://www.cnblogs.com/codershell
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果您觉得对您有帮助,不要忘了推荐一下哦~