选择排序
选择排序是一种简单直接的排序算法,其实质是在未排序序列中找到最小(大)元素,将其放在已排序序列的末尾(开始)位置。
算法步骤
以每次找到最大元素的方法为例:
- 从前到后,在未排序序列中查找最大元素,将该最大元素与序列末尾数据进行交换;
- 再从剩余未排序元素中继续寻找最大元素,将该最大元素与已排序序列前一个元素进行交换,即将该元素放在已排序序列开始的位置;
- 重复第2步,直到所有元素均排序完毕。
算法描述
//arrPtr为指向数组的指针,arrLen为数组长度
void selection_sort(int* arrPtr, int arrLen)
{
if (!arrPtr)
return;
for (int i = arrLen - 1; i > 0; --i)
{
int maxIndex = 0;//每次排序默认第一个元素为最大元素
int j = 0;
for (; j <= i; ++j)
{
//更新当前未排序序列中最大元素的index
if (arrPtr[j] > arrPtr[maxIndex])
maxIndex = j;
}
//当最大元素不是当前比较序列中最后一个元素时,交换当前比较序列最后一个元素与最大元素的位置
if (maxIndex != j - 1)
swap(arrPtr, maxIndex, j - 1);
}
}
上述算法中swap函数是为了交换数组中两元素位置的函数,其实现在前一篇《冒泡排序详解》博客中有详细实现,读者需要可翻看一下那篇博客。
排序过程演示
算法分析
时间复杂度
假定数组元素个数:n,比较次数:C,交换次数:M。
选择排序每趟都需要通过比较来定位当前未排序序列中的最大值,其总的比较次数为:C=(n-1) + (n-2) + … + 1 = n(n-1)/2。
若所有元素均正序排列,则每趟比较后不需要发生交换,此时交换次数Mmin=0。
若所有元素均反序排列,则每趟比较后均需发生一次交换,此时交换次数均为:Mmax=n-1。
综上,冒泡排序平均时间复杂度为O(n2),但其交换次数比冒泡排序少很多,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。
算法稳定性
选择排序每次从前到后寻找最大元素的位置,若两个元素相等,只会记录到第一个元素为最大元素,并将该元素交换到已排序序列开始位置;下一轮比较时找到刚才相等的另一元素,也将该元素交换到已排序序列开始位置;也就是说对于相同元素,原序列中先出现的元素在排序后成为排序序列中后出现的元素,前后顺序发生了变化,所以选择排序是一种不稳定排序算法。