各種簡單排序演算法模版
基於比較的排序(複雜度下界nlogn)
氣泡排序
時間複雜度 最壞O(n) 平均O(n^2) 最好O(n)
空間複雜度 O(1)
穩定
void bubbleSort(int *a, int n) { for (int i = n - 1, t; i; i = t) { t = i; for (int j = 0; j + 1 <= i; j++) if (a[j] > a[j + 1]) { swap(a[j], a[j + 1]); t = j; } } }
選擇排序
時間複雜度 最壞O(n^2) 平均O(n^2) 最好O(n^2)
空間複雜度 O(1)
穩定
void selectionSort(int *a, int n) { for (int i = 0; i < n - 1; i++) { int mini = i; for (int j = i + 1; j < n; j++) if (a[j] < a[mini]) mini = j; //swap(a[mini], a[i]); //不穩定 int t = a[mini]; //穩定 for (int j = mini; j > i; j--) a[j] = a[j - 1]; a[i] = t; } }
插入排序
時間複雜度 最壞O(n^2) 平均O(n^2) 最好O(n)
空間複雜度 O(1)
穩定
void insertionSort(int *a, int n) { for (int i = 1; i < n; i++) { int t = a[i], j; /*for (j = i - 1; j >= 0; j--) if (a[j] > t) a[j + 1] = a[j]; else break;*/ for (j = i - 1; j >= 0 && a[j] > t; j--) a[j + 1] = a[j]; a[j + 1] = t; } }
希爾排序
時間複雜度 O(nlogn) ?
空間複雜度 O(1)
不穩定
void shellSort(int *a, int n) { //已被淘汰
int gap = 1;
while (gap < n / 3) {
gap = gap * 3 + 1;
}
for (; gap; gap = gap / 3) //列舉間隔
for (int i = 0; i < gap; i++) //列舉每一組
for (int j = i + gap; j < n; j += gap) { //插入排序
int t = a[j], k;
for (k = j - gap; k >= 0 && a[k] > t; k -= gap)
a[k + gap] = a[k];
a[k + gap] = t;
}
}
歸併排序
時間複雜度 最壞O(nlogn) 平均O(nlogn) 最好O(nlogn)
空間複雜度 top down vector: O(n + logn) list: O(logn)
bottom up vector: O(n) list: O(1)
穩定
void mergeSort(int *a, int l, int r) {
if (l >= r) return;
int mid = l + r >> 1;
mergeSort(a, l, mid), mergeSort(a, mid + 1, r);
int *A = a + l, *B = a + mid + 1;
int lc = mid - l + 1, lb = r - mid;
int C[lc];
memcpy(C, A, sizeof(int) * lc);
int i = 0, j = 0, k = 0;
while (k < lc && j < lb) {
if (C[k] <= B[j]) A[i++] = C[k++];
else A[i++] = B[j++];
}
while (k < lc) A[i++] = C[k++];
}
快速排序
時間複雜度 最壞O(n^2) 平均O(nlogn) 最好O(nlogn)
空間複雜度 最壞O(n) 平均O(logn) 最好O(logn)
不穩定
void qSort(int *a, int l, int r) {
if (l == r) return;
int i = l - 1, j = r + 1, p = a[l + r >> 1];
while (i < j) {
while (a[++i] < p);
while (a[--j] > p);
if (i < j) swap(a[i], a[j]);
}
qSort(a, l, j), qSort(a, j + 1, r);
}
堆排序
時間複雜度 最壞O(nlogn) 平均O(nlogn) 最好O(nlogn)
空間複雜度 遞迴實現O(logn) or 迭代實現O(1)
不穩定
void down(int *h, int u, int n) {
int t = u;
if (2 * u <= n && h[2 * u] > h[t]) t = 2 * u;
if (2 * u + 1 <= n && h[2 * u + 1] > h[t]) t = 2 * u + 1;
if (t != u) {
swap(h[t], h[u]);
down(h, t, n);
}
}
void heapSort(int *a, int n) {
for (int i = n / 2; i; i--) down(a, i, n);
while (n) {
swap(a[1], a[n--]);
down(a, 1, n);
}
}
不基於比較的排序
計數排序
時間複雜度、空間複雜度與有關
穩定?
void countingSort(int *a, int n) {
const int N = 100000;
int c[N] = {0};
for (int i = 0; i < n; i++) c[a[i]]++;
for (int i = 0, t = 0; i < N; i++) //0 <= a[i] <= N - 1
while (c[i]--) a[t++] = i;
}
桶排序
是一種思想。
基本思路是:
1.將待排序元素劃分到不同的桶,先掃描一遍序列求出最大值maxV和最小值minV,設桶的個數為 k ,則把區間[minV, maxV]均勻劃分成k個區間,每個區間就是一個桶。將序列中的元素分配到各自的桶。
2.對每個桶內的元素進行排序。可以選擇任意一種排序演算法。
3.將各個桶中的元素合併成一個大的有序序列。
假設資料是均勻分佈的,則每個桶的元素平均個數為n/k 。假設選擇用快速排序對每個桶內的元素進行排序,那麼每次排序的時間複雜度為 O(n/klog(n/k)) 。總的時間複雜度為O(n) + k * O(n/klog(n/k)) = O(n + nlog(n/k)) = O(n + nlogn - nlogk) 。當 k 接近於 n 時,桶排序的時間複雜度就可近似認為是 O(n) 的。即桶越多,時間效率就越高,而桶越多,所需空間就越大。
基數排序
時間複雜度 最壞O(n) 平均O(n) 最好O(n)
空間複雜度 O(n) ?
穩定
void radixSort(int *a, int n) {
for (int i = 0; i < 10; i++) {
vector<int> b[10];
for (int j = 0; j < 10; j++) b[j].clear();
for (int j = 0; j < n; j++)
b[get(a[j], i)].push_back(a[j]);
for (int j = 0, l = 0; j < 10; j++)
for (int k = 0; k < b[j].size(); k++)
a[l++] = b[j][k];
}
}