1. 程式人生 > 實用技巧 >各種簡單排序演算法模版

各種簡單排序演算法模版

基於比較的排序(複雜度下界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];
    }
}