本文會通過Java語言實現:冒泡排序,插入排序,選擇排序,歸併排序,快速排序,桶排序,計數排序,基數排序,希爾排序
1 分析排序算法
1.1 執行效率
- 最好的情況,最壞的情況,平均情況時間複雜度
- 時間複雜度的係數,常數,低階
- 比較次數和交換次數
1.2 算法的內存消耗
算法的內存消耗我們可以通過空間複雜度來度量。
原地排序算法,就是特指空間複雜度是O(1)的排序算法。
1.3 排序算法的穩定性
如果序列中有值相等的元素, 經過排序之後,相等元素之間原有的先後順序不變化。
2 冒泡排序
穩定排序算法,原地排序算法,時間複雜度:O(n^2)
冒泡排序操作相鄰的兩個數據,每次冒泡操作都會對相鄰的兩個元素進行比較,看是否滿足大小關係。每次冒泡都能選出最大的或者最小的值。
/**
* 冒泡排序
* @param arr
* @return
*/
public static int[] bubbleSort(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
int n = arr.length;
// 總共需要循環n次 每次通過冒泡 得到最大的
for (int i = 0; i < n; i++) {
// 因爲上一次已經確定了最大的,所以需要遍歷的數據就是(n-1)-i
boolean flag = true;
for (int j = 0; j < (n - 1) - i ; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = false;
}
}
// 因爲冒泡 如果這次冒泡沒有數據沒有交換所以數據已經有序了,可以提前退出
if (flag) {
break;
}
}
return arr;
}
3 插入排序
穩定排序算法,原地排序算法,時間複雜度O(n^2)
根據,把位置的元素,插入在有序的集合中,插入的時候根據元素位置大小。
首先:講數組中的數據分爲兩個區間,已排序區間和未排序區間。初始已排序區間只有一個元素就是數組的第一個元素。
/**
* 插入排序
* @param arr
* @return
*/
public static int [] insertSort(int [] arr){
if (arr==null||arr.length==0) {
return null;
}
int n = arr.length;
// n從一1開始表示a[0]屬於有序序列
for (int i = 1; i < n; i++) {
// 當前需要比較的數字
int value = arr[i];
// 需要比較的次數
int j = i-1;
// 查找插入的位置
for (; j>=0; j--) {
if (arr[j]>value) {
// 數據移動
arr[j+1] = arr[j];
}else {
// 插入排序前面是有序序列,所有不需要移動數據的時候,直接跳出比較下個數字
break;
}
}
// 插入數據
arr[j+1] = value;
}
return arr;
}
4 選擇排序
不是穩定排序算法,原地排序算法,時間複雜度是O(n^2)
每次會從未排序區間中找到最小元素,將其放到已排序區間的末尾
/**
* 選擇排序
* @param arr
* @return
*/
public static int [] selectionSort(int [] arr){
if (arr==null||arr.length==0) {
return null;
}
int n = arr.length;
int temp = 0;
int minKey = 0;
// 剛開始沒有有序區間,所以從0開始
for (int i = 0; i < n; i++) {
minKey = i;
// 尋找無序區間最小的元素
for (int j = i+1; j < n; j++) {
if (arr[j]<arr[minKey]) {
minKey = j;
}
}
// 交換位置
temp = arr[i];
arr[i] = arr[minKey];
arr[minKey] = temp;
}
return arr;
}
未完,待續