基於比較的排序最好的時間複雜度爲O(N*lgN),證實以下: git
每種基於比較的排序都可以使用決策樹描述其排序過程,每一個節點最多有2個子節點。 算法
該決策樹的樹葉的最大值即爲全部可能的排序結果之和,即N的階乘N!。 shell
決策樹的高度h即爲比較的次數,由於二叉樹節點數最多爲2^h,因此有N! <= 2^h,根據斯特林公式可知: ubuntu
h >= lgN! >= lg(N/e)^N = N*lg(N/e) = N*lgN - N*lge 數組
所以算法複雜度最好爲: 測試
O(N*lgN - N*lge) = O(N*lgN) spa
若是要追求效率更高的排序算法,好比線性排序,就要使用其餘的非基於比較的排序算法。 code
本文用C實現了兩種線性排序算法,分別爲計數排序Counting Sort 和 基數排序 Radix Sort。這兩種算法的實現要求排序元素爲整數。 排序
計數排序包括兩步:計數和分配。首先對每一個元素出現的次數進行計數,而後設置前綴數組得知每一個元素在完成排序的數組中的位置,最後依照前綴數組進行元素分配。 it
能夠證實,計數排序的時間複雜度爲O(k+n),其中k爲元素最大值,n爲元素個數。
計數排序簡單實現以下:
/* Counting Sort include two steps: * Countint and Distribution. */ void countingSort(int arr[], size_t nmeb) { int i; int max; int countArr[max]; int prefixArr[max]; int holdArr[nmeb]; max = arr[0]; for (i = 1; i < nmeb; i++) { if (max < arr[i]) max = arr[i]; } /* initialize countint array */ for (i = 0; i < max; i++) countArr[i] = 0; /* step 1: counting */ for (i = 0; i < nmeb; i++) countArr[arr[i]]++; /* bulid prefix array */ prefixArr[0] = countArr[0]; for (i = 1; i < max; i++) prefixArr[i] = countArr[i] + prefixArr[i - 1]; /* step 2: distribution */ for (i = nmeb - 1; i >= 0; i--) { holdArr[prefixArr[arr[i]] - 1] = arr[i]; prefixArr[arr[i]]--; } /* copy array */ for (i = 0; i < nmeb; i++) arr[i] = holdArr[i]; }
好比, 對 (132, 321, 123)進行排序,按照10進制進行分層。
按照個位排序: 321,132,123
按照十位排序: 321,123,132
按照百位排序: 123,132,321
排序完成。
然而,不可以僅僅按照10或者2做爲位數進行分層,這會形成大量的分層,以致於要耗費屢次計數排序。
假設數組的最大值爲k,並且2^b>=k 且 2^(b-1)<=k,咱們要算出最優的分層位數r(二進制)。
可知,時間的複雜度爲所分層數b/r與計數排序時間複雜度O(n+k)的乘積,即
O(b/r*(n+k)) = O(b/r*(n+2^b))
經過求導或者其餘方法可知r=lgn時,值最優。
按照上面所述,基數排序的實現以下:
void countingSortBits(int arr[], size_t nmeb, int bits, int digits) { int i, max; max = 1 << bits; int countArr[max]; int prefixArr[max]; int holdArr[nmeb]; int copyArr[nmeb]; /* copy array hold one digits of original array */ for (i = 0; i < nmeb; i++) copyArr[i] = arr[i] % (1 << ((digits + 1) * bits)) / (1 << (digits * bits)); /* initialize countint array */ for (i = 0; i < max; i++) countArr[i] = 0; /* step 1: counting */ for (i = 0; i < nmeb; i++) countArr[copyArr[i]]++; /* bulid prefix array */ prefixArr[0] = countArr[0]; for (i = 1; i < max; i++) prefixArr[i] = countArr[i] + prefixArr[i - 1]; /* step 2: distribution */ for (i = nmeb - 1; i >= 0; i--) { holdArr[prefixArr[copyArr[i]] - 1] = arr[i]; prefixArr[copyArr[i]]--; } /* copy array */ for (i = 0; i < nmeb; i++) arr[i] = holdArr[i]; } int radixSort(int arr[], size_t nmeb) { int i, r, k, max; max = arr[0]; for (i = 1; i < nmeb; i++) { if (max < arr[i]) max = arr[i]; } for (r = 1; (nmeb >> r) > 0; r++) ; for (k = 1; (max >> k) > 0; k++) ; for (i = 0; i * r < k; i++) countingSortBits(arr, nmeb, r, i); }
簡單測試:
int main() { int i; int arr[10] = {89767, 12389, 13289, 12833, 11289, 87263, 48928, 12932, 32674, 65323}; printf("Original:\n"); for (i = 0; i < 10; i++) printf("%6d", arr[i]); printf("\n"); radixSort(arr, 10); printf("Sorted:\n"); for (i = 0; i < 10; i++) printf("%6d", arr[i]); printf("\n"); return 0; }
執行結果以下:
roo@ubuntu:~$ ./a.out Original: 89767 12389 13289 12833 11289 87263 48928 12932 32674 65323 Sorted: 11289 12389 12833 12932 13289 32674 48928 65323 87263 89767