本文内容基于《漫画算法 小灰的算法之旅》,魏梦舒著。
1. 分类
1.1 时间复杂度为O(n^2)的排序算法
- 冒泡排序
- 选择排序
- 插入排序
- 希尔排序(略优于O(n^2),但又低于O(nlogn),姑且归入本类)
1.2 时间复杂度为O(nlogn)的排序算法
- 快速排序
- 归并排序
- 堆排序
1.3 时间复杂度为线性的排序算法
- 计数排序
- 桶排序
- 基数排序
1.4 稳定性
如果值相同的元素在排序后仍然保持着排序前的顺序,那么这种排序算法是稳定排序,反之是不稳定排序。
1.5 本文中涉及的排序总结
排序算法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
冒泡排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
鸡尾酒排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
快速排序 | O(nlogn) | O(n^2) | O(logn) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
计数排序 | O(n+m) | O(n+m) | O(m) | 稳定 |
桶排序 | O(n) | O(nlogn) | O(n) | 稳定 |
2. 冒泡排序
2.1 思想
把相邻的元素两两比较,当一个元素大于右侧相邻元素时,交换它们的位置,当一个元素小于或等于右侧相邻元素时,位置不变。
例如以下待排序序列:
- 第1轮(详细)
- 第2轮-第7轮
2.2 代码实现
public class SortTest {
public static void bubbleSort(int[] array) {
//-1是因为最后一轮不需要排序
for (int i = 0; i < array.length - 1; i++) {
//-i是因为每一轮都能确定排序好一个数
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
//交换
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
public static void main(String[] args) {
int[] array = new int[]{5, 8 ,6, 3, 9, 2, 1, 7};
bubbleSort(array);
System.out.println(Arrays.toString(array));
}
}
2.3 代码优化1
从上图中可以看出,第6轮排序后就已经是有序的了,可是算法还是进行了第7轮排序。
public class SortTest {
public static void bubbleSort1(int[] array) {
//-1是因为最后一轮不需要排序
for (int i = 0; i < array.length - 1; i++) {
boolean isSorted = true;
//-i是因为每一轮都能确定排序好一个数
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
//交换
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
//还在进行交换,表示未有序,还需要进行下一轮
isSorted = false;
}
}
if (isSorted) {
break;
}
}
}
public static void main(String[] args) {
int[] array = new int[]{5, 8 ,6, 3, 9, 2, 1, 7};
//bubbleSort(array);
bubbleSort1(array);
System.out.println(Arrays.toString(array));
}
}
【注】因为序列原因,优化后的代码还是执行了7轮。作用情况是如果在第5轮结束的时候就已经有序了,那么程序只会进行到第6轮就停止,不会再进行第7轮,是这个意思。
2.4 代码优化2
参考以下待排序序列:
按照冒泡排序的思想,第1轮只会交换4和2、4和1的位置,第2轮只会交换3和2、3和1的位置...
说明的问题是:其实右边的许多元素已经是有序的了,但是程序不知道,他还是按照每一轮只会确定一个元素的顺序来执行,就造成了每一轮白白地比较了许多次。
public class SortTest {
public static void bubbleSort2(int[] array) {
//-1是因为最后一轮不需要排序
int sortedBorder = array.length - 1;
for (int i = 0; i < array.length - 1; i++) {
boolean i