目录
各内排序算法时空复杂度对比表
算法 | 最好 | 平均 | 最好 | 空间复杂 | 稳定 |
---|---|---|---|---|---|
插入 | O(n) | O(n²) | ← | O(1) | 是 |
选择 | O(n²) | ← | ← | ↑ | |
冒泡 | O(n) | O(n²) | ← | ↑ | 是 |
希尔 | - | O(n1.3) | - | ↑ | |
快排 | O(nlog₂n) | ← | O(n²) | O(log₂n) | |
堆排 | ↑ | ← | ← | O(1) | |
归并 | ↑ | ← | ← | O(n) | 是 |
基数 | O(d(n+r)) | ← | ← | O(r) | 是 |
源码
package top.senseiliu.codesnippet;
public final class SortUtils {
private SortUtils() {
}
// 输出数组
public static void printNum(int[] num) {
for (int item : num) {
System.out.print(item + " ");
}
System.out.println();
}
/**
* 直接插入法
* 从第二个元素开始遍历(正序)
* 对当前元素向前遍历(倒序)
* 如果前一个值大于当前值,把当前位置值置为前一个值,继续向前遍历
* 最后把当前值插回去
*
* @param num
*/
public static void insertSort(int[] num) {
for (int i = 1; i < num.length; ++i) {
int curNum = num[i];
int preIndex = i - 1;
while (preIndex >= 0 && num[preIndex] > curNum) {
num[preIndex + 1] = num[preIndex];
--preIndex;
}
num[preIndex + 1] = curNum;
}
}
/**
* 简单选择法
* 从第一个元素遍历到倒数第二个
* 从当前元素下标的下一个下标开始遍历,得到一个最小值的下标
* 如果当前元素下标不等于当前元素下标,则交换两值
*
* @param num
*/
public static void selectSort(int[] num) {
for (int i = 0; i < num.length - 1; ++i) {
int minIndex = i;
for (int j = i + 1; j < num.length; ++j) {
if (num[j] < num[minIndex]) {
minIndex = j;
}
}
if (i != minIndex) {
int minValue = num[minIndex];
num[minIndex] = num[i];
num[i] = minValue;
}
}
}
/**
* 冒泡排序法-普通版
*
* @param num
*/
public static void bubbleSort(int[] num) {
for (int i = 0; i < num.length - 1; ++i) {
for (int j = num.length - 1; j > i; --j) {
if (num[j - 1] > num[j]) {
int tmp = num[j];
num[j] = num[j - 1];
num[j - 1] = tmp;
}
}
}
}
/**
* 冒泡排序法-优化版
* 一次都没有产生交换说明数组基本有序直接退出
*
* @param num
*/
public static void bubbleSortOptimized(int[] num) {
boolean sorted;
for (int i = 0; i < num.length - 1; ++i) {
sorted = true;
for (int j = num.length - 1; j > i; --j) {
if (num[j - 1] > num[j]) {
int tmp = num[j];
num[j] = num[j - 1];
num[j - 1] = tmp;
sorted = false;
}
}
if (sorted) {
return;
}
}
}
/**
* 交换排序法
*
* @param num
*/
public static void exchangeSort(int[] num) {
for (int i = 0; i < num.length - 1; ++i) {
for (int j = i + 1; j < num.length; ++j) {
if (num[i] > num[j]) {
int tmp = num[i];
num[i] = num[j];
num[j] = tmp;
}
}
}
}
/**
* 希尔排序法
* 基于直接插入法
* 根据间隔分组,使用直接插入法
* 缩小间隔,直到为1,数组基本有序
*
* @param num 数组
*/
public static void shellSort(int[] num) {
int gap = num.length / 2;
while (gap > 0) {
for (int i = gap; i < num.length; ++i) {
int curNum = num[i];
int j = i - gap;
while (j >= 0 && num[j] > curNum) {
num[j + gap] = num[j];
j -= gap;
}
num[j + gap] = curNum;
}
gap /= 2;
}
}
/**
* 快速排序法
* 选定一个元素作为基准点,这里选beginIndex作为基准元素
* 对数组两端开始与基准元素比较,向中间靠拢
* 当两指针停止移动,交换两值继续向中间靠拢
* 当两指针在同一下标时,将该下标值与基准元素值交换
* 将该下标值左右两边的数组再做递归快排
*
* @param num 数组
* @param beginIndex 起始下标
* @param endIndex 结束下标
*/
public static void quickSort(int[] num, int beginIndex, int endIndex) {
int i = beginIndex;
int j = endIndex;
if (i < j) {
int base = num[i];
while (i != j) {
while (j > i && num[j] >= base) {
--j;
}
num[i] = num[j];
while (i < j && num[i] <= base) {
++i;
}
num[j] = num[i];
}
num[i] = base;
quickSort(num, beginIndex, i - 1);
quickSort(num, i + 1, endIndex);
}
}
/**
* 调整为大顶堆
*
* @param num 数组
* @param curIndex 将该节点所在的子树调整为大顶堆
* @param maxRange 将被调整的最大范围
*/
public static void sift(int[] num, int curIndex, int maxRange) {
int i = curIndex;
int j = i * 2;
int tmp = num[i];
while(j <= maxRange) {
if (j < maxRange && num[j + 1] > num[j]) {
++j;
}
if (num[j] > tmp) {
num[i] = num[j];
i = j;
j = i * 2;
} else {
break;
}
}
num[i] = tmp;
}
/**
* 堆排序
* 数组中的第一个元素(下标为0)不参与排序
* 如new int[]{0, 5, 4, 3, 2, 1}数组
* 排序后为{0, 1, 2, 3, 3, 4}
*
* @param num 数组,第一个元素需要为空的
*/
public static void heapSort(int[] num) {
for (int i = (num.length - 1) / 2; i >= 1; --i) {
sift(num, i, num.length - 1);
}
for (int i = num.length - 1; i >= 2; --i) {
int tmp = num[1];
num[1] = num[i];
num[i] = tmp;
sift(num, 1, i - 1);
}
}
}
源码地址:
https://gitee.com/feistel/Blog/tree/master/Java/code/CodeSnippet/code-snippet