一、直接选择排序
1.排序思想
直接选择排序是最简单的排序方法,排序思想最直接。
要点:(1)该方法将数组分为有序部分和无序部分,初始时数组全为无序状态;
(2)每次遍历数组中无序部分,并找出其中的最小值,将最小值交换到有序部分的下一位;
(3)在经过n-1次遍历和比较之后就能够得到排序好的数组。
如上图所示,需要从无序部分a3,a4……a(n-1)中找出最小值(假如为a6),然后将a6与a3交换位置,使得前面的有序部分元素个数加一(a0,a1,a2,a6),而无序部分元素个数减一(a4,a5,a3,...,a(n-1)),如此循环,便可得到排序结果。
2.代码实现
//直接选择排序
void selectionSort(int arr[], int n)
{
int minIndex;
for(int i=0; i<n-1; i++) //外层n-1次遍历,i表示当前无序部分第一个元素下标
{
minIndex = i;
for (int j=i+1; j<n; j++) //内层循环通过j遍历无序部分找到最小值
{
if (arr[j] < arr[minIndex])
{
minIndex = j;
}
}
if (i != minIndex) //将最小值交换至有序部分的下一位(当前无序部分的第一位)
{
int tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
}
}
在代码中需要注意的是,有的算法实现中没有比较i与minIndex的值是否相等,而直接进行交换,这样可以使代码更加简洁。但是这时候需要注意一个问题,那就是交换算法的选择。首先介绍常用的三种交换变量的算法。
void swap1(int &a, int &b) //借用第三个变量,形参需要为引用(或指针)
{
int tmp = a;
a = b;
b = tmp ;
}
void swap2(int &a, int &b) //不借用第三变量,采用加减运算,形参需要为引用(或指针)
{
a = a + b;
b = a - b;
a = a - b;
}
void swap3(int &a, int &b) //不借用第三变量,采用异或运算,形参需要为引用(或指针)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
这三种算法中,第一种算法需要借助第三个变量作为缓存,也是最常见的方法。后面两种算法不需要额外的变量辅助,而且第三种交换算法因为采用位操作,速度会更快。
回到正题,如果没有比较i与minIndex的值而直接交换,有可能造成需要交换的两个值是同一数组元素。这时候第一种交换算法是可行的,第二种交换算法理论上也是可行的(如果考虑极端情况,数组元素特别大,元素相加后可能造成溢出,这时候该方法就不可行了),但是第三种交换算法却一定不可行,因为同一个元素相互异或运算,会将该元素清零,而无法达到交换的目的。
综上所述,如果你没有强迫症(需要代码简洁),还是建议加上一句比较判断。
3.性能分析
时间复杂度:O(n^2)。
由代码可以看出,它的移动次数比较少(最多n-1次)。主要开销在数据比较上,外层循环需要n-1次遍历,每次遍历中需要进行n-i次比较,忽略数据移动的时间(常数),总时间为(n-1)*(n-i),i是从0到n-2,那么,可以得到时间复杂度O(n^2)。无论最好情况、最坏情况和平均情况,比较次数都不变,所以选择排序的时间复杂度O(n^2)。
空间复杂度:O(1)。
特点:稳定的就地排序(稳定性与代码有关)。
适用性:小规模数组排序。
本文在参考别人基础上完成,下面为链接地址:
http://blog.csdn.net/touch_2011/article/details/6767673