目录
生词解释
概念 | |
原地排序 | 空间复杂度是O(1)的排序算法 |
稳定性 | 排序后,相等元素间先后顺序不变(例子:订单,下单时间、订单金额) |
几种常用的排序算法比较
排序算法 | 时间复杂度 | 是否基于比较 |
冒泡、插入、选择 | O(n2) | 是 |
快排、归并 | O(nlogn) | 是 |
桶、计数、基数 | O(n) | 否 |
排序算法的执行效率分析方法
- 最好、最坏、平均情况时间复杂度都要考虑(因为出现的情况可能各个情况都有)
- 时间复杂度的系数、常数、低阶
- 比较次数和交换(或移动)次数(如何考虑?系数、常数、低阶不是已经考虑了?)
排序算法分析
是否原地排序 | 是否稳定排序 | 最好时间复杂度 | 最坏时间复杂度 | 平均时间复杂度 | |
冒泡 | 是(只用了temp) | 是(大小相等,不交换) | O(n)(顺序已经排好) | O(n2)(倒序) | (交换次数)逆序度 = 满有序度-有序度(加权平均算法比较困难) |
插入 | 是 | 是 | O(n)(顺序已经排好) | O(n2)(倒序) | |
选择 | |||||
冒泡排序
方式:比较两个相邻的数字,如果第一个数字比第二个数组大则交换位置,第一轮将最大的值放到指定的位置(优化:如果发现某次冒泡没有数据交换表示数据已经排好了,不用再继续了);
实现:
// 冒泡排序,a 表示数组,n 表示数组大小
public void bubbleSort(int[] a, int n) {
if (n <= 1) return;
for (int i = 0; i < n; ++i) {
// 提前退出冒泡循环的标志位
boolean flag = false;
for (int j = 0; j < n - i - 1; ++j) {
if (a[j] > a[j+1]) { // 交换
int tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
flag = true; // 表示有数据交换
}
}
if (!flag) break; // 没有数据交换,提前退出
}
}
插入排序
方式:将数组分为已排序区间(初始只有数组中的第一个元素)和未排序区间,将未排序区间的数据与已排序的元素比较大小,找到插入的位置
实现:
// 插入排序,a 表示数组,n 表示数组大小
public void insertionSort(int[] a, int n) {
if (n <= 1) return;
for (int i = 1; i < n; ++i) {
int value = a[i];
int j = i - 1;
// 查找插入的位置
for (; j >= 0; --j) {
if (a[j] > value) {
a[j+1] = a[j]; // 数据移动
} else {
break;
}
}
a[j+1] = value; // 插入数据
}
}