选择排序
原理:
从头至尾扫描序列,找出最小的一个元素,和第一个元素交换,接着从剩下的元素中继续这种选择和交换方式,最终得到一个有序序列。
思路:
- 在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
- 第二次遍历n-2个数,找到最小的数值与第二个元素交换;
- ……
- 第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。
图解选择排序:
算法分析:
-
排序算法:
先从头遍历一遍找出最小元素,最小元素和第一个元素相交换。再从第二个元素遍历到最后一个元素找出最大元素,最小元素和第二个元素相交换。直到所有元素都有序为止。 -
选择排序的优缺点:
优点:一轮比较只需要换一次位置;
缺点:效率慢,不稳定 -
时间复杂度
选择排序的交换操作介于 0 和 (n - 1) 次之间。选择排序的比较操作为 n (n - 1) / 2 次之间。选择排序的赋值操作介于 0 和 3 (n - 1) 次之间。比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+…+1=n*(n-1)/2。
综上所述:选择排序总的平均时间复杂度为:O(n^2)比较次数O(n^2),交换次数O(n),最好情况是已经有序,交换0次;最坏情况交换n-1次。交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。
算法稳定性
选择排序即是给每个位置选择待排序元素中当前最小的元素。比如给第一个位置选择最小的,在剩余元素里面给第二个位置选择次小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。
那么,在选择时,如果当前锁定元素比后面一个元素大,而后面较小的那个元素又出现在一个与当前锁定元素相等的元素后面,那么交换后位置顺序显然改变了。
举个例子:序列5 8 5 2 9, 我们知道第一趟选择第1个元素5会与2进行交换,那么原序列中两个5的相对先后顺序也就被破坏了。
综上所述:
选择排序是一种不稳定排序算法。
C代码实现:
#include <stdio.h>
#include <stdlib.h>
//打印函数
void printArr(int arr[], int sz){
int i;
for (i = 0; i < sz; i++){
printf("%d ", arr[i]);
}
printf("\n");
}
//选择排序函数
void selectSort(int a[], int n)
{
int min, tmp;
int i, j;
//每次循环数组,找出最小的元素,放在前面,前面的即为排序好的
for (i = 0; i < n - 1; i++)
{
min = i; //假设最小元素的下标
for (j = i + 1; j < n; j++) {//将上面假设的最小元素与数组比较,交换出最小的元素的下标
if (a[j] < a[min])
min = j;
}
//若数组中真的有比假设的元素还小,就交换
if (i != min)
{
tmp = a[i];
a[i] = a[min];
a[min] = tmp;
}
}
}
int main(){
int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
printArr(arr, sz);
selectSort(arr, sz);
printArr(arr, sz);
system("pause");
return 0;
}
代码生成图:
如有不同见解,欢迎留言!