如果完成排序后,原本有序的元素不会改变其相对的位置,表示该排序是稳定的;如果完成排序后,原本有序的元素会改变其相对的位置,表示该排序是不稳定的
举个简单的例子,如果对[1, 2, 2, 3, 4]
进行排序,如下图所示:
public int[] sort(int[] nums) {
int n = nums.length;
for (int i = 0; i < n - 1; i++) { // 进行 n - 1 轮遍历,每次都将值最大元素挪到最右边
boolean isChange = false; // 标记是否有交换操作
for (int j = 0; j < n - i - 1; j++) { // 从头开始两两进行交换
if (nums[j] > nums[j + 1]) {
int t = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = t;
isChange = true;
}
}
if (!isChange) break; // 如果一轮一次交换都没发送,表示元素均有序,直接退出循环
}
return nums;
}
时间复杂度:
注意:如果数组已经有序,那么在第一轮遍历时就会退出循环,所以最好时间复杂度为
public int[] sort(int[] nums) {
int n = nums.length;
for (int i = 0; i < n; i++) {
int minId = i;
for (int j = i + 1; j < n; j++) {
if (nums[minId] > nums[j]) minId = j;
}
int t = nums[i];
nums[i] = nums[minId];
nums[minId] = t;
}
return nums;
}
时间复杂度:
关于不稳定,举个例子[7, 7, 2]
,那么第一轮交换后为[2, 7, 7]
,两个 7 的相对位置发生了变化
注意:该排序的时间复杂度与数组的特点无关,均为
public int[] sort(int[] nums) {
public int[] sortArray(int[] nums) {
int n = nums.length;
for (int i = 1; i < n; i++) {
int t = nums[i];
for (int j = i - 1; j >= 0; j--) {
if (nums[j] <= t) break;
nums[j + 1] = nums[j];
nums[j] = t;
}
}
return nums;
}
}
时间复杂度:
注意:如果数组已经有序,那么内层循环会第一时间退出,所以最好时间复杂度为
详情可见 详解归并排序及其应用
时间复杂度:
详情可见 详解快排及其应用
时间复杂度:
注意:如果数组已经有序,那么时间复杂度为
详情可见 详解堆排序「优先队列」
时间复杂度:
排序算法 | 平均时间复杂度 | 最好时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | 稳定 | ||||
选择排序 | 不稳定 | ||||
插入排序 | 稳定 | ||||
归并排序 | 稳定 | ||||
快速排序 | 不稳定 | ||||
堆排序 | 不稳定 |