排序算法
算法分类
比较类排序: 通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),也被称为非线性时间比较类排序
非比较类排序: 不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,也被称为线性时间非比较类排序
| 排序算法 | 比较类排序 | 交换排序 | 冒泡排序 |
| 快速排序 | |||
| 插入排序 | 简单插入排序 | ||
| 希尔排序 | |||
| 选择排序 | 简单选择排序 | ||
| 堆排序 | |||
| 归并排序 | 二路归并排序 | ||
| 多路归并排序 | |||
| 非比较排序 | 计数排序 | ||
| 桶排序 | |||
| 基数排序 | |||
算法复杂度
| 排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 |
|---|---|---|---|---|---|
| 插入排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
| 希尔排序 | O(n¹•³) | O(n²) | O(n) | O(1) | 不稳定 |
| 选择排序 | O(n²) | O(n²) | O(n²) | O(1) | 不稳定 |
| 堆排序 | O(nlog₂n) | O(nlog₂n) | O(nlog₂n) | O(1) | 不稳定 |
| 冒泡排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
| 快速排序 | O(nlog₂n) | O(n²) | O(nlog₂n) | O(nlog₂n) | 不稳定 |
| 归并排序 | O(nlog₂n) | O(nlog₂n) | O(nlog₂n) | O(n) | 稳定 |
| 计数排序 | O(n+k) | O(n+k) | O(n+k) | O(n+k) | 稳定 |
| 桶排序 | O(n+k) | O(n²) | O(n) | O(n+k) | 稳定 |
| 基数排序 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | 稳定 |
相关概念
稳定: 若a原本在b前面,而a=b,排序后a仍在b前面
不稳定: 若a原本在b前面,而a=b,排序后a可能出现在b后面
时间复杂度: 对排序数据的总的操作次数
空间复杂度: 指算法在计算机内执行时所需存储空间的度量,也是数据规模的函数
冒泡排序
依次比较相邻的两个元素,左边的元素若比右边的大,就将它俩的位置相互调换
动画演示
代码实现
public static List<Integer> bubbleSort(Integer... i) {
/* 临时变量 */
int snap;
/* 冒泡次数,排除排序可能出现的错误 */
for (int j = 0; j < i.length; j++) {
/* 冒泡排序 */
for (int l = 0; l < i.length - 1; l++) {
/* 与后一个数字比较大小,若这个数字大于下一个数字则将二者的顺序进行调换 */
if (i[l] > i[l + 1]) {
snap = i[l];
i[l] = i[l + 1];
i[l + 1] = snap;
}
}
}
return Arrays.asList(i);
}
选择排序
依次将从待排序的数组中选出最小的元素,将其放置到待排序的数组中的最左边
动画演示
代码实现
public static List<Integer> selectSort(Integer... i) {
int snap,
t /* 临时变量 */;
for (int j = 0; j < i.length; j++) {
/* 记录数组中最小值的下标 */
snap = j;
for (int l = snap + 1; l < i.length; l++)
/* 判断当前最小值是否大于后续值,若大于就将最小值的索引赋值给临时变量 */
if (i[snap] > i[l]) snap = l;
t = i[j];
i[j] = i[snap];
i[snap] = t;
}
return Arrays.asList(i);
}
快速排序
通过定位基准元素将待排序数组分成两部分,比关键字小和比关键字大的,再将这两部分通过递归达到有序排序的效果
动画演示
代码实现
public static List<Integer> quickSort(Integer[] i) {
quickSort(i, 0, i.length - 1);
return Arrays.asList(i);
}
private static void quickSort(Integer[] i, Integer start, Integer end) {
/* 当条件不满足时,跳出程序,避免堆栈溢出 */
if (start > end) return;
/* 变量定义 */
int datum = i[start],
j = start,
l = end,
temporary;
while (j < l) {
/* 获取比基准元素小的元素在数组中的索引 */
while (datum <= i[l] && j < l) l--;
/* 获取比基准元素大的元素在数组中的索引 */
while (datum >= i[j] && j < l) j++;
if (j < l) {
temporary = i[l];
i[l] = i[j];
i[j] = temporary;
}
}
/* 将基准元素与j、k相等的索引处的数字交换 */
i[start] = i[j];
i[j] = datum;
/* 递归调用当前基准元素左边的数组 */
quickSort(i, start, j - 1);
/* 递归调用当前基准元素右边的数组 */
quickSort(i, j + 1, end);
}
插入排序
从数组的索引1开始,将数组中待排序的元素按照升序规则插入到已排序好的数组中
动画实现
代码实现
public static List<Integer> insertionSort(Integer... i) {
/* 临时变量 */
int temporary;
/* 从索引1处循环整个数组 */
for (int j = 1; j < i.length; j++) {
/* 倒序循环已排序的数组 */
for (int l = j; l > 0; l--) {
/* 与已排序的数组元素进行对比,当前元素小于上一个元素,就与其进行位置调换 */
if (i[l] < i[l - 1]) {
temporary = i[l];
i[l] = i[l - 1];
i[l - 1] = temporary;
}
}
}
return Arrays.asList(i);
}
以下仅为动画演示,暂未进行研究
计数排序
动画演示
代码实现
在这里插入代码片
基数排序
动画演示
代码实现
在这里插入代码片
归并排序
动画演示
代码实现
在这里插入代码片
堆排序
动画演示
代码实现
在这里插入代码片