距上一次热血澎湃看算法已经过去两年了,如果不是看到马老师最近开始讲算法了估计还会继续遗忘下去。
先备份一张图,来源:http://www.mashibing.com(欢迎大家访问马老师网站)
这次来学习选择排序,顾名思义,选择排序当然是选择为主。举例说明。
5 6 1 4 3 ↑
选择这几个数中的最小(大)的数:1,放到最前(后)面即和首(尾)位交换
1 6 5 4 3 ↑
然后再除了1之后选择最小的数:3,放到第二的位置。
1 3 5 4 6 ↑
循环下去,最后得到1 3 4 5 6的数组即可。
用代码实现:
//选择排序 void selectSort(int num[],int len) { int i = 0,j = 0; int minIndex = 0; for(i = 0;i < len;i++) { //假设首部数值为最小值 minIndex = i; for(j = i + 1;j < len;j++) { if(num[j] < num[minIndex]) { //找到最小的值 minIndex = j; } } //把最小的值和首部进行交换 int temp = num[i]; num[i] = num[minIndex]; num[minIndex] = temp; } }
非常简单易懂的算法,但是由马老师的图可知该算法是不稳定的,什么叫做不稳定呢?就是两个相等的值,在排序之后位置可能发生变化,让我们写个例程测试一下
struct student { int age; char name[20]; }; void main() { int i = 0,j = 0,minIndex = 0; //注意在初始化的时候,有两个结构体的age都是4,但是test4 first位置在 test4 last前面 struct student all[] = { {4,"test4 first"}, {3,"test3"}, {4,"test4 last"}, {2,"test2"}, {1,"test1"}, }; for(i = 0;i < 5;i++) { minIndex = i; for(j = i + 1;j < 5;j++) { if(all[j].age < all[minIndex].age) { minIndex = j; } } struct student temp = all[minIndex]; all[minIndex] = all[i]; all[i] = temp; } for(i = 0;i < 5;i++) { printf("%s,",all[i].name); } printf("\n"); }
运行结果
test1,test2,test3,test4 last,test4 first
很明显,test4 first和test4 last的位置反了,这就是不稳定造成的结果,举个例子,A现在银行存了5万,B也在银行存了5万,理论上查询存5万的第一人应该是A,但是经过这个排序算法之后查询到的却是B,后面的问题可想而知。
优化:马老师提示其中一种优化方法可以是一次找到最大值和最小值,把最小值放到前面,最大值放到后面不就把循环次数缩小一半了吗。
用代码实现:
//优化选择排序 void selectSortFindMinAndMax(int num[],int len) { int i = 0,j = 0,k = 0,m = 0; int minIndex = 0,maxIndex = 0; for(i = 0;i < len / 2;i++) { minIndex = i; maxIndex = i; for(j = i + 1;j < len - k;j++) { if(num[j] < num[minIndex]) { //找到最小值 minIndex = j; } if(num[j] > num[maxIndex]) { //找到最大值 maxIndex = j; } } //考虑如果最大值就是i下标,如果先交换最小值,则会把最大值位置的数值改变 //这种情况应该先交换最大值。 if((maxIndex == i) && (minIndex != len - k - 1)) { swap(num,len - k - 1,maxIndex); swap(num,i,minIndex); } //考虑如果最大值是i下标,最小值是循环尾,则只用交换一次即可。 else if((maxIndex == i) && (minIndex == len - k - 1)) { swap(num,maxIndex,minIndex); } //其余情况先交换最小值,再交换最大值 else { swap(num,i,minIndex); swap(num,len - k - 1,maxIndex); } //循环一次之后,循环尾向前移 k++; } }
两种方法的循环次数以及时间比较(数组大小10000,有rand()随机产生):
系统函数0.001000ms,普通选择0.111000ms循环49995000次,优化选择0.083000ms循环25000000次 系统函数0.002000ms,普通选择0.115000ms循环49995000次,优化选择0.071000ms循环25000000次 系统函数0.002000ms,普通选择0.112000ms循环49995000次,优化选择0.077000ms循环25000000次 系统函数0.002000ms,普通选择0.106000ms循环49995000次,优化选择0.081000ms循环25000000次 系统函数0.001000ms,普通选择0.111000ms循环49995000次,优化选择0.077000ms循环25000000次 系统函数0.001000ms,普通选择0.119000ms循环49995000次,优化选择0.093000ms循环25000000次 系统函数0.002000ms,普通选择0.113000ms循环49995000次,优化选择0.088000ms循环25000000次 系统函数0.001000ms,普通选择0.110000ms循环49995000次,优化选择0.074000ms循环25000000次 系统函数0.001000ms,普通选择0.112000ms循环49995000次,优化选择0.075000ms循环25000000次 系统函数0.001000ms,普通选择0.114000ms循环49995000次,优化选择0.076000ms循环25000000次