距上一次热血澎湃看算法已经过去两年了,如果不是看到马老师最近开始讲算法了估计还会继续遗忘下去。
先备份一张图,来源: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次