目录
写在前面的话
小伙伴们大家好啊!这里是小菜鸡森哩,今天为大家带来的是排序算法中的选择排序。其中包含之前我们有实现过的堆排序。那么接下来我们一起看看吧!
一,选择排序
那么对于选择排序来说,思路依然是比较简单的,如下图所示(升序为例):
1.1思路实现
我们的思路是首先在一组数中找出最大数和最小数,然后将最大数放在最右边,而将最小的数放在最左边,然后将排序范围缩小到最大数和最小数之间,依次排序之后,最后排序范围指针 begin 和 end 指向一个数时,或者当 begin 大于 end,说明排序完成。
步骤一
那么首先这里我们需要两个指针 begin 和 end,begin 从数组首元素开始,end 从数组最后一个元素开始,同时我们先假定最大数的下标 maxi 和最小数的下标 mini 就是第一个元素下标。
然后就是依次遍历数组,找到最大的数的下标和最小数的下标,然后再将最大数和 end 位置元素交换,将最小数和 begin 位置元素交换,这样我们的数组第一次排序就完成了,我们将最大数和最小数分别放在了两边:
步骤二
此时第一个步骤就完事了,接下来我们将 begin 和 end 的位置缩小到小范围数组,再次进行排序。然后就是一直缩小范围,直到指针 begin 和 end 指向一个数时,或者当 begin 大于 end,此时整个数组就排完序了。
tips:
这里我们还需要注意一个点,有可能最大数就是首元素位置,那么当我们循环之后就会出现下面的情况:
此时最大元素位置和首元素位置重合,如果我们依旧还是像上面那样去移动的话,则会将 26 这个最大数移动到 当前 1 的位置,然后再会将 1 移动到数组末尾位置,这样明显是错误的,所以这里我们需要在交换完最小值和首元素之后,修正一下 maxi 的位置到 mini 位置,然后再去交换数组尾元素和 maxi 位置的值。
1.2代码实现
//选择排序
void SelectSort(int *a,int n)
{
assert(a);
int begin = 0, end = n - 1, i = 0;
while (begin < end)
{
//maxi 和 mini 初始值需要在 begin 和 end 的区间内
//所以两个值的初始值只能为 begin ,不能写 0
int maxi = begin, mini = begin;
for (i = begin; i <= end ; i++)
{
if (a[i] < a[begin])
mini = i;
if (a[i] > a[end])
maxi = i;
}
swap(&a[mini],&a[begin]);
if (begin == maxi)
maxi = mini;
swap(&a[maxi],&a[end]);
begin++;
end--;
}
}
1.3复杂度以及稳定性
复杂度:
那么我们知道,对于直接选择排序而言,因为每次我们都需要选择出较大数和较小数,然后将他们移动,所以这里选择和移动最坏的时候,都是需要遍历一次当前范围的数组的,所以时间复杂度为O(N^2)。而因为当前排序没有开辟空间,所以空间复杂度是O(1)。
稳定性:
因为每次遍历选择和移动都是需要移动元素的,而且小的会直接移动到前面去,所以相对位置变化是比较大的,所以直接选择排序是不稳定的。
二,堆排序
堆排序的思想也是一种选择排序的思路,同样是选出最值数,然后缩小排序范围,依次排序。
那么对于堆排序而言,在之前堆的文章里面,我们有详细的解读。堆结构的两个重要应用(topk问题,堆排序)_菜还不承认的库森的博客-CSDN博客
好的,那么对于选择排序我们就了解到这里。如有问题,还请指正呀!