排序 就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
平时的上下文中,如果提到排序,通常指的是排升序(非降序)。
通常意义上的排序,都是指的原地排序(in place sort)。
稳定性 指两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法是具备稳
定性的排序算法。
基于比较的七种排序
插入排序
原理
整个区间被分为
- 有序区间
- 无序区间
每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入
代码实现
// 最好的情况:数组有序
// 最坏的情况:数组倒序
// 最好情况的时间复杂度:O(n)
// 最坏情况的时间复杂度:O(n ^ 2)
// 平均情况的时间复杂度:O(n ^ 2)
// 能否保证稳定性:能保证稳定性
// 空间复杂度:O(1)
public static void insertSort(long[] array) {
for (int i = 1; i < array.length; i++) {
// 有序区间: [0, i)
// 无序区间: [i, array.length)
// 1. 把无序区间的第一个数 [i] 插入到有序区间
long key = array[i];
int j;
for (j = i - 1; j >= 0 && array[j] > key; j--) {
array[j + 1] = array[j];
}
// for (j = i - 1; j >= 0; j--) {
// if (array[j] < key) {
// // key 应该插入到 [j + 1]
// break;
// } else if (array[j] == key) {
// // key 应该插入到 [j + 1]
// break;
// } else {
// // j 继续往前
// }
//
// array[j + 1] = array[j];
// }
array[j + 1] = key;
}
}
性能分析
最好的情况:数组有序
最坏的情况:数组倒序
最好情况的时间复杂度:O(n)
最坏情况的时间复杂度:O(n ^ 2)
平均情况的时间复杂度:O(n ^ 2)
能否保证稳定性:能保证稳定性
空间复杂度:O(1)
选择排序
原理
每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排
序的数据元素排完 。
代码实现
// 不区分最好/平均/最坏情况
// 时间复杂度:O(n ^ 2)
// 空间复杂度:O(1)
// 能否保证稳定性:不能保证稳定性
public static void selectSort(long[] array) {
for (int i = 0; i < array.length - 1; i++) {
// 无序区间: [0, array.length - i)
// 在无序区间中,找出最大的数所在的下标
// 通过遍历查找
int maxIndex = -1;
for (int j = 0; j < array.length - i; j++) {
if (maxIndex == -1 || array[j] > array[maxIndex]) {
maxIndex = j;
}
}
// 交换 最大数[maxIndex] 和 无序区间的最后一个数[array.length - i - 1]
swap(array, maxIndex, array.length - i - 1);
}
}
性能分析
不区分最好/平均/最坏情况
时间复杂度:O(n ^ 2)
空间复杂度:O(1)
能否保证稳定性:不能保证稳定性
冒泡排序
原理
在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序
代码实现
// 最好的情况:数组有序
// 最坏的情况:数组倒序
// 最好情况的时间复杂度:O(n)
// 最坏情况的时间复杂度:O(n ^ 2)
// 平均情况的时间复杂度:O(n ^ 2)
// 能否保证稳定性:能保证稳定性
// 空间复杂度:O(1)
public static void bubbleSort(long[] array) {
for (int i = 0; i < array.length - 1; i++) {
// 无序区间: [0, array.length - i)
// 每次冒泡过程之前,都假设数组已经有序
boolean sorted = true;
// 执行一次冒泡过程 —— 需要比较无序区间元素的次数 - 1 次
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
swap(array, j , j + 1);
sorted = false;
}
}
if (sorted) {
// 假设成立,无序区间确实已经有序了
return;
}
}
}
性能分析
最好的情况:数组有序
最坏的情况:数组倒序
最好情况的时间复杂度:O(n)
最坏情况的时间复杂度:O(n ^ 2)
平均情况的时间复杂度:O(n ^ 2)
能否保证稳定性:能保证稳定性
空间复杂度:O(1)