時空複雜度:
冒泡排序:時間O(n^2),額外空間O(1)
插入排序:時間O(n^2),額外空間O(1)
選擇排序:時間O(n^2),額外空間O(1)
基數排序:時間O(k*n)(k=logN_max),額外空間O(n)(臨時儲存)+O(B)(記數,B為基的大小)
記數排序:時間O(n+k),額外空間O(k)
希爾排序:時間O(n*logn^2),額外空間O(1)
快速排序:時間O(n*log(n)),額外空間O(logn)(遞迴棧)
歸併排序:時間O(n*log(n)),額外空間O(n)(臨時數組)+O(logn)(遞迴棧)
堆排序: 時間O(n*log(n))
使快速排序退化的例子:
n, n-1, n-2, n-3.......3,2,1,快速排序具有O(n^2)的複雜度。
最佳化方法:隨機播放劃分元素,而不是固定選擇最左面的元素。
對歸併來說,一個很不理想的例子:
1,2,3,…… , n
對有序序列還是需要O(nlogn)的時間複雜度。
最佳化方法:找到序列的連續自增段,把這樣的自增段進行合并。
穩定排序和不穩定排序
穩定的排序演算法:冒泡排序、插入排序、基數排序、記數排序、歸併排序
非穩定排序演算法:希爾排序、選擇排序、快速排序、堆排序
實際上穩定排序可以實現成非穩定的,看具體的實現過程。有些同學誤以為自己寫了一個冒泡排序就是穩定的,注意比較的時候是">=" 還是">"。
內部排序與外部排序
http://zh.wikipedia.org/zh/%E5%A4%96%E6%8E%92%E5%BA%8F
內部排序:內部排序是指待排序列完全存放在記憶體中所進行的排序過程,適合不太大的元素序列。
外部排序:外部排序指的是大檔案的排序,即待排序的記錄儲存在外儲存空間上,待排序的檔案無法一次裝入記憶體,需要在記憶體和外部儲存空間之間進行多次資料交換,以達到排序整個檔案的目的。最常用的外部排序是多路歸併排序。對於外部排序,影響速度的最主要因素為訪問磁碟的次數,所以設計外部排序演算法時,儘可能減少訪問磁碟的次數。
對於外部排序多路歸併演算法的時間複雜度進行簡要分析。
設有n個數,分成k段,之後利用m路歸併 。
t1 = n*log(n/k) 每段分別排序 n*log(n/k)。
t2 = n*logk 每趟對n個數合并(每個數每趟只操作一次),一共logk趟,
t3 = n * (T_read + T_write) * logk 從檔案中讀取和寫入數字花費的時間,
設每讀取一個數的耗時為T_read,每次寫一個數耗時為T_write,
T(n) = t1 + t2+t3 = n*log(n/k) + n*logk + n*(T_read+T_write)*logk ,其中logk是以m為底的。
所以,為了減少訪問磁碟的次數,必須增大基m,但是m並不是越大越好,如果越大,則在m個數中選擇最大值會越慢,所以一般都選m=9。
逆序數問題
對於序列 x1,x2,x3.......xn
若存在i>j,且滿足x[i] < x[j],則稱(x[i],x[j])構成一個逆序對, 一個序列所有的逆序對的數目叫做這個序列的逆序數。
例如序列 :5 4 3 2 1
逆序數為 1+2+3+4 = 10
利用歸併排序可以快速的求得一個序列的逆序數。
尋找第K大數演算法
問題1:給出一個序列,求這個序列第K大的數(離線)
比較通用的演算法:
(1) 利用快速排序的劃分。每次可以省去一部分的數進行尋找。
設下一次的尋找百分比為q<1,
時間 T(n) = n + T(n*q)
= n + n*q + T(n*q^2)
= n + n*q + n*q^2 + T(n*q^3)
......
= n(1 + q + q^2 + q^3 + ......)
= n(1*(1-q^k)/(1-q))
當q=1/2時, T(n) = 2n = O(n)。
這種方法最壞情況下的時間複雜度是O(n^2)。
那麼有沒有能夠保證最壞時間複雜度是O(n)的演算法嗎?有
(2) 最壞時間下是O(n)複雜度的演算法
http://en.wikipedia.org/wiki/Selection_algorithm 或參見<<演算法導論>> P190-P191
針對普通的劃分和隨機化劃分的缺點,對選擇劃分數進行改進:選擇中位元的中位元進行劃分。
假設函數Find(A, k, n)返回的是A數組中第k大的元素,新的尋找演算法如下:
1:將輸入數組的n個元素劃分為n/5組,每組5個元素,至多有一個組的元素數目小於5。
2:尋找n/5個組的每個組的中位元。對每個組的5個元素利用插入排序,之後選擇中位元。
3: 對第2步找到的n/5個中位元遞迴調用Find函數,找出其中位元x。
4:利用中位元x對輸入數組進行劃分。並得出x的排位。
5:如果第四步得到的x的排位為k,則返回x。如果x的排位大於k,則在低區進行遞迴尋找,否則在高區進行尋找。
因為x是中位元,除去x本身所在的組和那個元素數目小於5的組不算,大於x的元素數目至少為3*(1/2)*(n/5 - 2) = 3*n/10 - 6。
同理小於x的元素數目至少為3*n/10 - 6。那麼第4步最多有n-(3*n/10-6) = 7*n/10+6個元素參加下次的遞迴尋找。
設Find(A, k, n)花費時間為T(n)。
則T(n) = t1 + t2 + t3 + t4 + t5。
t1 = O(n) (分成n/5組)
t2 = O(n) (每組進行選擇可以看做O(1)時間花費)
t3 = T(n/5) (對n/5個中位元遞迴選擇)
t4 = O(n) (根據x進行劃分)
t5 = T(7*n/10 + 6) (下一次遞迴選擇)
T(n) = T(n/5) + T(7*n/10 + 6) + O(n)
最後可推算出T(n)=O(n),但是個人認為常數比較大。
K非常小時情況下的選擇第K大元素演算法:
利用冒泡或者選擇排序,時間複雜度O(K*n)。