目录
💓 博客主页:C-SDN花园GGbond
⏩ 文章专栏:探索数据结构与算法
一、算法思想
**选择排序(Selection Sort)**也是一种比较直观的排序,它通过每次遍历数组选出最小或最大元素,然后与起始或者末尾位置交换,不断缩小区间,依次循环达到排序的目的。
二、算法步骤
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
- 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
- 重复第二步,直到所有元素均排序完毕。
初始化:未排序区间为数组的全部元素,即整个数组;已排序区间为空。
遍历 :从未排序区间中遍历找到最小(或最大)的元素。
交换:将找到的最小(或最大)的元素与未排序区间的第一个元素进行交换,该元素即为未排序区间的最小值(或最大值),因此交换后,它就到了已排序区间的末尾。
缩小未排序区间:将未排序区间的第一个元素排除(因为它已经是排序好的了),继续在剩余的未排序区间中重复上述步骤,直到未排序区间为空。
图解
下图以升序排序为例进行演示
三、C语言实现代码
优化前
void swap(int* a, int* b)//交换函数
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void SelectSort1(int* a, int n)//选择排序降序
{
for (int i = 0; i < n - 1; i++)//控制选择次数
{
int mini = i;
for (int j = i + 1; j < n; j++)//控制查找范围
{
if (a[j] < a[mini])
mini = j;
}
swap(&a[i], &a[mini]);
}
}
代码优化
选择排序每一次选择的过程都需要遍历一遍数组,找出最大值(最小值),这样的时间消耗无法避免。但可以在每一次遍历数组时,同时选出最大值和最小值,分别放在数组的左右两侧.
这样优化之后,时间消耗可以减少一半,
需要注意的一点是:
最大值和最小值初始都以最前面的值开始向后进行比对,如果最大值就在初始位置,先将最小值交换之后,最大值就会被移走。
所以交换完最小值之后,就需要判断一下最大值是不是被交换走了,如果是的话,就要去最小值交换的位置找最大值
如下图所示
void swap(int* a, int* b)//交换函数
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void SelectSort(int* a, int n)//选择排序优化版——左右同时选择
{
int left = 0;
int right = n - 1;
while (left < right)//控制选择次数
{
int mini = left;
int maxi = left;
for (int i = left + 1; i <= right; i++)//控制查找范围
{
if (a[i]<a[mini])
mini = i;
if (a[i]>a[maxi])
maxi = i;
}
swap(&a[mini], &a[left]);
if (maxi == left)//如果最大值原本在left位置,mini的交换就将最大值换走了
maxi = mini;
swap(&a[maxi], &a[right]);
left++;
right--;
}
}
四、复杂度分析
- 时间复杂度:无论是优化前后,每次都需要遍历寻找最小或者最大元素,所以时间复杂度为O(N2)。
- 空间复杂度:没有开辟额外的空间大小,所以空间复杂度为O(1)。
总结
在众多排序算法中,选择排序以其简洁直观的特点而著称。尽管在效率上不是最优的,特别是对于大规模数据集而言,但选择排序的算法思想却蕴含着深刻的逻辑和广泛的应用场景。通过不断选择剩余元素中的最小(或最大)元素,并将其放置到序列的起始位置,选择排序以一种简单而直接的方式完成了数据的排序。