常见的排序
中文名称 | 英文名称 | 平均时间复杂度 | 最差时间复杂度 | 最好时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|---|
选择排序 | Selection | n 2 n^2 n2 | n 2 n^2 n2 | n 2 n^2 n2 | 1 | 不稳 |
冒泡排序 | Bubble | n 2 n^2 n2 | n 2 n^2 n2 | n n n | 1 | 稳 |
插入排序 | Insertion | n 2 n^2 n2 | n 2 n^2 n2 | n n n | 1 | 稳 |
堆排序 | heap | n l o g 2 n nlog_2^n nlog2n | n l o g 2 n nlog_2^n nlog2n | n l o g 2 n nlog2^n nlog2n | 1 | 不稳 |
希尔排序 | Shell | n 1.3 n^{1.3} n1.3 | n 2 n^2 n2 | n n n | 1 | 不稳 |
归并排序 | Merge | n l o g 2 n nlog_2^n nlog2n | n l o g 2 n nlog_2^n nlog2n | n l o g 2 n nlog_2^n nlog2n | n n n | 不稳 |
快速排序 | Quick | n l o g 2 n nlog_2^n nlog2n | n 2 n^2 n2 | n l o g 2 n nlog_2^n nlog2n | l o g 2 n log_2^n log2n | 不稳 |
桶排序 | Bucket | n + k n + k n+k | n 2 n^2 n2 | n n n | n + k n+k n+k | 稳 |
计数排序 | Counting | n + k n+k n+k | n + k n+k n+k | n + k n+k n+k | n + k n+k n+k | 稳 |
基数排序 | Radix | n ∗ k n*k n∗k | n ∗ k n*k n∗k | n ∗ k n*k n∗k | n + k n+k n+k | 稳 |
选择排序
最简单但也最没用的排序算法。
/**
* 选择排序
*/
public class SelectionSort {
public static void main(String[] args) {
int[] intArr = {5, 4, 5, 1, 3};
sort(intArr);
}
static void sort(int[] intArr) {
for (int i = 0; i < intArr.length - 1; i++) {
// 默认最小值是每次循环中的第一个值
int minIndex = i;
// 比较数组里的每个值是否小于最小值
for (int j = i + 1; j < intArr.length; j++) {
// 如果小于最小值,则它为最小值
if (intArr[j] < intArr[minIndex]) {
// 记录最小值的下标
minIndex = j;
}
}
swap(intArr, i, minIndex);
System.out.println("第"+(i+1)+"次循环,数组内容:");
print(intArr);
}
print(intArr);
}
/**
* 交换元素位置
* @param arr 数组
* @param i 位置1
* @param j 位置2
*/
static void swap(int[] arr, int i, int j) {
// 记录原最小值,用于和最小值互换
int temp = arr[i];
// 数组中原最小值换为新的最小值
arr[i] = arr[j];
// 最小值的位置换为原最小值
arr[j] = temp;
}
static void print(int arr[]) {
Arrays.stream(arr).forEach(num->{
System.out.print(num + " ");
});
System.out.println();
}
}
看上面的程序,数组长度是5,第一次循环时,需要比较4次;第二次循环,需要比较3次,第三次循环需要比较2,第四次循环需要比较1次,最终数组长度为5时比较的次数=4+3+2+1,那么数组长度为n时,需要比较的次数= ( n − 1 ) + ( n − 2 ) + . . . + 1 (n - 1) + (n - 2) + ... + 1 (n−1)+(n−2)+...+1,首尾相加= n ( n − 1 ) 2 n\frac{(n-1)}{2} n2(n−1),当n趋于无限大时,时间复杂度为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( 1 ) O(_1) O(1),因为没有用到额外的空间。
上面的程序还有优化的空间,每次循环找最小值的同时我也可以把最大值找出来,然后放在最后的位置,这样我只循环一半就排好序了。
package com.zyj.study.algorithm.sort;
import java.util.Arrays;
/**
* 选择排序--优化
*/
public class SelectionSort2 {
static int[] intArr = {9, 5, 4, 2, 1, 3, 8, 6, 7, 10};
public static void main(String[] args) {
print(intArr);
for (int i = 0; i < intArr.length - i - 1; i++) {
int minIndex = i;
int maxIndex = i;
for (int j = i + 1; j < intArr.length - i; j++) {
minIndex = intArr[j] < intArr[minIndex] ? j : minIndex;
maxIndex = intArr[j] > intArr[maxIndex] ? j : maxIndex;
System.out.println("min="+intArr[minIndex]+",max=" + intArr[maxIndex]);
}
swap(intArr, i, minIndex);
if (i == maxIndex) {
maxIndex = minIndex;
}
swap(intArr, intArr.length - i - 1, maxIndex);
System.out.println("第"+(i+1)+"次循环,数组内容:");
print(intArr);
}
}
/**
* 交换元素位置
* @param arr 数组
* @param i 位置1
* @param j 位置2
*/
static void swap(int[] arr, int i, int j) {
// 记录原最小值,用于和最小值互换
int temp = arr[i];
// 数组中原最小值换为新的最小值
arr[i] = arr[j];
// 最小值的位置换为原最小值
arr[j] = temp;
}
static void print(int arr[]) {
Arrays.stream(arr).forEach(num->{
System.out.print(num + " ");
});
System.out.println();
}
}
9 5 4 2 1 3 8 6 7 10
min=5,max=9
min=4,max=9
min=2,max=9
min=1,max=9
min=1,max=9
min=1,max=9
min=1,max=9
min=1,max=9
min=1,max=10
第1次循环,数组内容:
1 5 4 2 9 3 8 6 7 10
min=4,max=5
min=2,max=5
min=2,max=9
min=2,max=9
min=2,max=9
min=2,max=9
min=2,max=9
第2次循环,数组内容:
1 2 4 5 7 3 8 6 9 10
min=4,max=5
min=4,max=7
min=3,max=7
min=3,max=8
min=3,max=8
第3次循环,数组内容:
1 2 3 5 7 4 6 8 9 10
min=5,max=7
min=4,max=7
min=4,max=7
第4次循环,数组内容:
1 2 3 4 6 5 7 8 9 10
min=5,max=6
第5次循环,数组内容:
1 2 3 4 5 6 7 8 9 10
如果数组的长度是n,那么循环次数为 n 2 \frac{n}{2} 2n,当n趋于无限大,时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(_1) O(1),因为没有用到额外的空间。