本文我们直接说一个优化过的直接选择排序。其思路大同小异.
直接选择排序的特性总结:
void SelectSort(int* a, int n)
{
int begin = 0, end = n - 1; // 定义排序区间的起点和终点
while (begin < end) // 当起点小于终点时,继续排序
{
int maxi = begin, mini = begin; // 定义当前区间最大值和最小值的下标
for (int i = begin; i <= end; i++) // 遍历当前区间
{
if (a[i] > a[maxi]) // 如果当前元素大于最大值,更新最大值下标
{
maxi = i;
}
if (a[i] < a[mini]) // 如果当前元素小于最小值,更新最小值下标
{
mini = i;
}
}
Swap(&a[begin], &a[mini]); // 将最小值和当前区间起点交换位置
// 如果最大值下标和起点下标重叠,修正一下最大值下标即可
if (begin == maxi)
{
maxi = mini;
}
Swap(&a[end], &a[maxi]); // 将最大值和当前区间终点交换位置
++begin; // 起点向右移动一位
--end; // 终点向左移动一位
}
}
代码实现起来比较简单:
但是要注意一个点如果最大值下标和起点下标重叠,需要做一下处理.
if (begin == maxi)
{
maxi = mini;
}
这行代码的意思是判断最大值下标是否和起点下标重叠,如果重叠则最大值已经被移动到了最小值下标处了,需要将最大值下标更新为最小值下标,否则下一步交换操作会将最大值和起点处的元素交换,而不是最大值和终点处的元素交换。举个例子
当待排序数组为 {5, 2, 3, 4, 1} ,第一轮排序时,最小值为1,最大值为5,
第一次swap交换后数组变为 {1, 2, 3, 4, 5},在第二次swap交换时如果没有判断
:此时的最大值下标仍然指向起点位置,直接swap交换则数据会变成{5,2,3,4,1},导致排序错误。如加上判断:
更新maxi的下标, maxi = mini;此时maxi的下标指向了4,再次swap数据.排序成功。因此,需要判断最大值下标和起点下标是否重叠,如若重叠,需要将最大值下标更新为最小值下标,即maxi=mini。
if(begin == maxi)
成立,则maxi = mini;