所有的光鲜靓丽都敌不过时间,并且一去不复返。———— 菲茨杰拉德《了不起的盖茨比》
这是我参与更文挑战的第9天,活动详情查看: 更文挑战
一、算法思想
选择排序是一种暴力(brute force)排序算法,它在每次迭代中从未排序列表中选择最小的元素并将该元素放在未排序列表的开头。
二、工作流程
假设我们试图按升序对元素进行排序。
- 选择第一个元素作为最小元素
minimum
。
- 最小元素
minimum
与后续所有元素进行比较,找到最小的元素,将minimum
指向这个元素。
- 每次迭代后,
minimum
都放在未排序列表的前面。
- 对于每次迭代,索引从第一个未排序的元素开始。重复步骤 1 到 3,直到所有元素都放置在正确的位置。
三、选择排序代码实现
伪代码实现流程
selectionSort(array, size)
repeat (size - 1) times
set the first unsorted element as the minimum
for each of the unsorted elements
if element < currentMinimum
set element as new minimum
swap minimum with first unsorted position
end selectionSort
java 实现选择排序
import java.util.Arrays;
/**
* 选择排序
*
* @className: SelectSort
* @date: 2021/6/23 19:42
*/
public class SelectSort {
public static void main(String[] args) {
int[] arr = { 20, 12, 10, 15, 2 };
selectSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void selectSort(int[] arr) {
int length = arr.length;
// 循环的轮次:length - 1
for (int i = 0; i < length - 1; i++) {
// 选择每轮的第一个元素作为最小元素进行比较
int min_idx = i;
// 比较的次数:length - (i + 1),这里从 i + 1 开始
for (int j = i + 1; j < length; j++) {
if (arr[j] < arr[min_idx]) {
min_idx = j;
}
}
// 将最小元素和每轮的第一个元素交换位置
int temp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = temp;
}
}
}
四、选择排序复杂度
时间复杂度 | |
---|---|
最好 | O(n2) |
最差 | O(n2) |
平均 | O(n2) |
空间复杂度 | O(1) |
稳定 | 不 |
1. 时间复杂度的计算细节
循环 | 比较次数 |
---|---|
第一 | (n - 1) |
第二 | (n - 2) |
第三 | (n - 3) |
... | ... |
最后 | 1 |
因此,比较的次数是:(n-1) + (n-2) + (n-3) +.....+ 1 = n(n-1)/2
,几乎等于 n2,因此复杂性:O(n2)。此外,如果我们观察代码,有两个循环,因此复杂度为 n*n = n2
- 最坏情况复杂度 O(n2): 如果我们想将一个有序数组倒序排列,那么最坏的情况就会发生。
- 最佳案例复杂度 O(n2):如果数组已经排序,时间复杂度也是 O(n2)。
- 平均案例复杂度 O(n2): 当数组的元素处于混乱的顺序(既不升也不降)时,就会发生这种情况。
选择排序的时间复杂度在所有情况下都是相同的,在每一步都必须找到最小元素并将其放在正确的位置。
2. 空间复杂度
- 空间复杂度是O(1)因为额外的变量用于交换。
五、冒泡排序应用
选择排序在以下情况下使用
- 一个小列表要排序
- 交换成本无关紧要
- 检查所有元素是强制性的
选择排序是一种就地比较排序。它的时间复杂度为O(n2),这使得它在大型列表上效率低下,而且通常比类似的插入排序性能更差。选择排序以其简单性著称,在某些情况下,特别是在辅助内存有限的情况下,它比更复杂的算法具有性能优势。
参考文章: