標籤:處理 歸併 作用 依據 演算法分析 -- while sub 其他
排序簡介
排序是資料處理中經常使用的一種重要運算,在電腦及其應用系統中,花費在排序上的時間在系統已耗用時間中佔有很大比重; 並且排序本身對推動演算法分析的發展也起很大作用。
目前已有上百種排序方法,但尚未有一個最理想的盡如人意的方法,本章介紹常用的如下排序方法,並對它們進行分析和比較。
1、插入排序(直接插入排序、折半插入排序、希爾排序);
2、交換排序(起泡排序、快速排序);
3、選擇排序(直接選擇排序、堆排序);
4、歸併排序;
5、基數排序;
我們所練習的排序主要是內部排序,所謂內部排序,就是整個排序過程都在記憶體進行的排序,稱為 內部排序;
反之,若排序過程中要進行資料的內、外存交換, 則稱之為 外部排序。
內排序適用於記錄個數不是很多的小檔案,而外排序則適用於記錄個數太多,不能一次性放人記憶體的大檔案。
對排序演算法的分析可以從以下幾個方面進行:排序演算法的穩定性、平均時間、最壞情況、輔助儲存空間。
從穩定性來說,穩定的排序演算法有: 直接插入排序、 冒泡排序、 歸併排序, 其它排序演算法都是不穩定的。
平均時間 最好情況 最壞情況 輔助空間
直接插入排序 O(n*n) O(n) O(n*n) O(1)
希爾排序排序 O(n1+£) O(n) O(n*n) O(1)
£是介於0和1之間的常數
冒泡排序 O(n*n) O(n) O(n*n) O(1)
快速排序 O(nlogn) O(nlogn) O(n*n) O(nlogn)
直接選擇排序 O(n*n) O(n*n) O(n*n) O(1)
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1)
歸併排序 O(nlogn) O(nlogn) O(nlogn) O(1)
各種排序方法比較
簡單排序中 直接插入最好(穩定、易於實現),
快速排序最快,
當檔案為正序時, 直接插入 和 冒泡均最佳。
(1)若n較小(如n≤50),可採用直接插入或直接選擇排序。
當記錄規模較小時,直接插入排序較好;否則因為直接選擇移動的記錄數少於直接插人,應選直接選擇排序為宜。
(2)若檔案初始狀態基本有序(指正序),則應選用直接插人、冒泡或隨機的快速排序為宜;
(3)若n較大,則應採用時間複雜度為O(nlgn)的排序方法:快速排序、堆排序或歸併排序。
快速排序 是目前基於比較的內部排序中被認為是最好的方法,當待排序的關鍵字是隨機分布時,快速排序的平均時間最短;
堆排序 所需的輔助空間少於快速排序,並且不會出現快速排序可能出現的最壞情況。這兩種排序都是 不穩定的。
若要求排序穩定,則可選用歸併排序。
但本章介紹的從單個記錄起進行兩兩歸併的排序演算法並不值得提倡,通常可以將它和直接插入排序結合在一起使用。
先利用直接插入排序,,求得較長的有序子檔案,然後再兩兩歸併之。 因為直接插入排序是穩定的,所以改進後的歸併排序仍是穩定的。
排序(sort)或分類
所謂排序,就是要整理檔案中的記錄,使之按關鍵字遞增(或遞減)次序排列起來。其確切定義如下:
輸入:n個記錄R1,R2,…,Rn,其相應的關鍵字分別為K1,K2,…,Kn。
輸出:Ril,Ri2,…,Rin,使得Ki1≤Ki2≤…≤Kin。(或Ki1≥Ki2≥…≥Kin)。
1.被排序對象--檔案 被排序的對象--檔案由一組記錄組成。
記錄則由若干個資料項目(或域)組成。其中有一項可用來標識一個記錄,稱為關鍵字項。該資料項目的值稱為關鍵字(Key)。
注意: 在不易產生混淆時,將關鍵字項簡稱為關鍵字。
2.排序運算的依據--關鍵字 用來作排序運算依據的關鍵字,可以是數字類型,也可以是字元類型。
關鍵字的選取應根據問題的要求而定。
【例】在高考成績統計中將每個考生作為一個記錄。每條記錄包含准考證號、姓名、各科的分數和總分數等項內容。
若要惟一地標識一個考生的記錄,則必須用"准考證號"作為關鍵字。
若要按照考生的總分數排名次,則需用"總分數"作為關鍵字
排序的穩定性
當待排序記錄的關鍵字均不相同時,排序結果是惟一的,否則排序結果不唯一。
在待排序的檔案中,若存在多個關鍵字相同的記錄,經過排序後這些具有相同關鍵字的記錄之間的相對次序保持不變,該排序方法是穩定的;
若具有相同關鍵字的記錄之間的相對次序發生變化,則稱這種排序方法是不穩定的。
注意: 排序演算法的穩定性是針對所有輸入執行個體而言的。即在所有可能的輸入執行個體中,只要有一個執行個體使得演算法不滿足穩定性要求,則該排序演算法就是不穩定的
穩定意思是說原本索引值一樣的元素排序後相對位置不變
學習的時候,可能編的程式裡面要排序的元素都是簡單類型,實際上真正使用的時候,可能是對一個複雜類型的數組排序,而排序的鍵實際上只是這個元素中的一個屬性,
對於一個簡單類型,數字值就是其全部意義,即使交換了也看不出什麼不同。。。但是對於複雜的類型,交換的話可能就會使原本不應該交換的元素交換了。。比如,一個“學生”數組,按照年齡排序,“學生”這個對象不僅含有“年齡”,還有其他很多屬性,穩定的排序會保證比較時,如果兩個學生年齡相同,一定不交換。
判斷方法
對於不穩定的排序演算法,只要舉出一個執行個體,即可說明它的不穩定性;
而對於穩定的排序演算法,必須對演算法進行分析從而得到穩定的特性。
需要注意的是,排序演算法是否為穩定的是由具體演算法決定的,不穩定的演算法在某種條件下可以變為穩定的演算法,
而穩定的演算法在某種條件下也可以變為不穩定的演算法。
例如,對於如下起泡排序演算法,原本是穩定的排序演算法,如果將記錄交換的條件改成r[j]>=r[j+1],則兩個相等的記錄就會交換位置,從而變成不穩定的演算法。
void BubbleSort(int r[ ], int n){
exchange=n; //第一趟起泡排序的範圍是r[1]到r[n]
while (exchange) //僅當上一趟排序有記錄交換才進行本趟排序
{
bound=exchange; exchange=0;
for (j=1; j if (r[j]>r[j+1]) {
r[j]←→r[j+1];
exchange=j; //記錄每一次發生記錄交換的位置
}
}
}
再如,快速排序原本是不穩定的排序方法,但若待排序記錄中只有一組具有相同關鍵碼的記錄,而選擇的軸值恰好是這組相同關鍵碼中的一個,此時的快速排序就是穩定的
不同條件下,排序方法的選擇
(1)若n較小(如n≤50),可採用直接插入或直接選擇排序。 當記錄規模較小時,直接插入排序較好;否則因為直接選擇移動的記錄數少於直接插人,應選直接選擇排序為宜(2)若檔案初始狀態基本有序(指正序),則應選用直接插人、冒泡或隨機的快速排序為宜;(3)若n較大,則應採用時間複雜度為O(nlgn)的排序方法:快速排序、堆排序或歸併排序。 快速排序是目前基於比較的內部排序中被認為是最好的方法,當待排序的關鍵字是隨機分布時,快速排序的平均時間最短; 堆排序所需的輔助空間少於快速排序,並且不會出現快速排序可能出現的最壞情況。這兩種排序都是不穩定的。 若要求排序穩定,則可選用歸併排序。但本章介紹的從單個記錄起進行兩兩歸併的 排序演算法並不值得提倡,通常可以將它和直接插入排序結合在一起使用。先利用直接插入排序求得較長的有序子檔案,然後再兩兩歸併之。因為直接插入排序是穩定的,所以改進後的歸併排序仍是穩定的。 4)在基於比較的排序方法中,每次比較兩個關鍵字的大小之後,僅僅出現兩種可能的轉移,因此可以用一棵二叉樹來描述比較判定過程。 當檔案的n個關鍵字隨機分布時,任何藉助於"比較"的排序演算法,至少需要O(nlgn)的時間。 箱排序和基數排序只需一步就會引起m種可能的轉移,即把一個記錄裝入m個箱子之一,因此在一般情況下,箱排序和基數排序可能在O(n)時間內完成對n個記錄的排序。 但是,箱排序和基數排序只適用於像字串和整數這類有明顯結構特徵的關鍵字,而當關鍵字的取值範圍屬於某個無窮集合(例如實數型關鍵字)時,無法使用箱排序和基數排序,這時只有藉助於"比較"的方法來排序。 若n很大,記錄的關鍵字位元較少且可以分解時,採用基數排序較好。雖然桶排序對關鍵字的結構無要求,但它也只有在關鍵字是隨機分布時才能使平均時間達到線性階,否則為平方階。同時要注意,箱、桶、基數這三種分配排序均假定了關鍵字若為數字時,則其值均是非負的,否則將其映射到箱(桶)號時,又要增加相應的時間。 (5)有的語言(如Fortran,Cobol或Basic等)沒有提供指標及遞迴,導致實現歸併、快速(它們用遞迴實現較簡單)和基數(使用了指標)等排序演算法變得複雜。此時可考慮用其它排序。 (6)本章給出的排序演算法,輸人資料均是儲存在一個向量中。當記錄的規模較大時,為避免耗費大量的時間去移動記錄,可以用鏈表作為儲存結構。 譬如插入排序、歸併排序、基數排序都易於在鏈表上實現,使之減少記錄的移動次數。 但有的排序方法,如快速排序和堆排序,在鏈表上卻難於實現,在這種情況下,可以提取關鍵字建立索引表,然後對索引表進行排序。然而更為簡單的方法是:引人一個整型向量t作為輔助表,排序前令t[i]=i(0≤i<n), 若排序演算法中要求交換R[i]和R[j],則只需交換t[i]和t[j]即可;排序結束後,向量t就指示了記錄之間的循序關聯性: R[t[0]].key≤R[t[1]].key≤…≤R[t[n-1]].key 若要求最終結果是: R[0].key≤R[1].key≤…≤R[n-1].key 則可以在排序結束後, 再按輔助表所規定的次序重排各記錄,完成這種重排的時間是O(n)。
排序簡介