Transcript 第7章排序
第七章 排序 課前指引 「排序」(Sorting)是指將一群資料,按特定規則調換位置, 使資料具有某種次序關係(遞增或遞減),例如資料庫內可針對 某一欄位進行排序,而此欄位稱為「鍵(key)」,欄位裡面的值 我們稱之為「鍵值(key value)」。 章節大綱 7-1 排序簡介 7-2 內部排序法 7-3 外部排序法 備註:可依進度點選小節 7-1 排序簡介 在排序的過程中,資料的移動方式可分為 「直接移動」及「邏輯移動」兩種。 「直接移動」是直接交換儲存資料的位置。 「邏輯移動」並不會移動資料儲存位置,僅改變 指向這些資料的輔助指標的值。 直接移動排序 邏輯移動排序 3 7-1 排序簡介 排序的分類 就排序法的選擇來說,當資料量相當大時,排序 演算法所花費的時間就顯得相當重要;一個排序 法是否為一種有效率(Efficiency)的排序法,取 決於其時間複雜度,而時間複雜度的決定因素則 是排序過程中資料的交換次數及比較次數的多寡。 排序前:21 排序後:81 34 77 45 56 56 45 77 34 81 21 這種排序的時間複雜度就是最壞情況 4 7-1 排序簡介 時間複雜度 最好情況(Best Case) 一次遞增排序所使用的時間複雜度就是資料已完成排序, 例如原本資料已經完成遞增排序了,如果再進行最好情 況。 最壞情況(Worst Case) 指每一鍵值均須重新排列,簡單的例子如原本為遞增排 序重新排序成為遞減,就是最壞情況。 平均情況(Average Case) 空間複雜度就是指演算法在執行過程所需付出的額外記 憶體空間,排序法所使用到的額外空間愈少,它的空間 複雜度就愈佳。 5 7-2 內部排序法 穩定的排序 指資料在經過排序後,兩個相同鍵值的記錄仍然 保持原來的次序,如下例中30左的原始位置在30 右的左邊(所謂30左及30右是指相同鍵值一個在 左一個在右),穩定的排序(Stable Sort)後7左 仍應在7右的左邊,不穩定排序則有可能30左會跑 到30右的右邊去: 原始資料順序: 穩定的排序: 10 不穩定的排序: 30左 21 10 10 30左 21 65 30右 30右 30右 65 30左 21 65 6 7-2 內部排序法 氣泡排序法 又稱為交換排序法,是由觀察水中氣泡變化構思 而成,原理是由第一個元素開始,比較相鄰元素 大小,若大小順序有誤,則對調後再進行下一個 元素的比較,就彷彿氣泡逐漸由水底逐漸冒升到 水面上一樣。 以下排序利用 55、23、87、62、16數列的排序過 程,可以清楚知道氣泡排序法的演算流程: • 由小到大排序: 7 7-2 內部排序法 • 第一次掃瞄會先拿第一個元素55和第二個元素23作比較, 如果第二個元素小於第一個元素,則作交換的動作。 • 接著拿55和87作比較,就這樣一直比較並交換,到第4 次比較完後即可確定最大值在陣列的最後面。 8 7-2 內部排序法 • 第二次掃瞄亦從頭比較起,但因最後一個元素在第一次 掃瞄就已確定是陣列最大值,故只需比較3次即可把剩 餘陣列元素的最大值排到剩餘陣列的最後面。 9 7-2 內部排序法 • 第三次掃瞄完,完成三個值的排序 • 第四次掃瞄完,即可完成所有排序 由此可知5個元素的氣泡排序法必須執行5-1次掃 瞄,第一次掃瞄需比較5-1次,共比較4+3+2+1=10 次 10 7-2 內部排序法 範例 7.2.1 數列(43,35,12,9,3,99)經由氣泡排序法(Bubble Sort)由小到大排序,在執行時前三次(Swap)的結 果各為何? 解答 第一次交換的結果為(35,43,12,9,3,99) 第二次交換的結果為(35,12,43,9,3,99) 第三次交換的結果為(35,12,9,43,3,99) 11 7-2 內部排序法 氣泡法分析 1.最壞清況及平均情況均需比較:(n-1)+(n-2)+(n3)+…+3+2+1=n(n-1)/2 次;時間複雜度為O(n2),最好情 況只需完成一次掃瞄,發現沒有做交換的動作則表示已經 排序完成,所以只做了n-1次比較,時間複雜度為O(n)。 2.由於氣泡排序為相鄰兩者相互比較對調,並不會更改其 原本排列的順序,所以是穩定排序法。 3.只需一個額外的空間,所以空間複雜度為最佳。 4.此排序法適用於資料量小或有部份資料已經過排序。 12 7-2 內部排序法 範例 7.2.2 請設計一Java程式,並使用氣泡排序法來將以下 的數列排序,並輸出逐次排序的結果: 6,5,9,7,2,8 13 7-2 內部排序法 範例 7.2.3 以上範例7.2.2程式可以看出氣泡排序法有個缺點, 就是不管資料是否已排序完成都固定會執行n(n1)/2次。 請設計一修改後的Java程式,可以藉由在程式中 加入判斷式來判斷何時可以提前中斷程式,又可 得到正確的資料,來增加程式執行效能。 14 7-2 內部排序法 15 7-2 內部排序法 選擇排序法 以下利用55、23、87、62、16數列的由小到大排 序過程,來說明選擇排序法的演算流程: 1.首先找到此數列中最小值後與第一個元素交換: 2.從第二個值找起,找到此數列中(不包含第一個)的最 小值,再和第二個值交換: 16 7-2 內部排序法 3.從第三個值找起,找到此數列中(不包含第一、二個) 的最小值,再和第三個值交換: 4.從第四個值找起,找到此數列中(不包含第一、二、三 個)的最小值,再和第四個值交換,則此排序完成: 17 7-2 內部排序法 選擇法分析 1.無論是最壞清況、最佳情況及平均情況都需要找到最 大值(或最小值),因此其比較次數為:(n-1)+(n-2)+(n3)+…+3+2+1= 次;時間複雜度為O(n2) 2.由於選擇排序是以最大或最小值直接與最前方未排序 的鍵值交換,資料排列順序很有可能被改變,故不是穩 定排序法。 3.只需一個額外的空間,所以空間複雜度為最佳。 4.此排序法適用於資料量小或有部份資料已經過排序。 18 7-2 內部排序法 範例 7.2.4 請設計一Java程式,並使用選擇排序法來將以下 的數列排序: 9,7,5,3,4,6 19 7-2 內部排序法 插入排序法 是將陣列中的元素,逐一與已排序好的資料作比 較,如前兩個元素先排好,再將第三個元素插入 適當的位置,所以這三個元素仍然是已排序好, 接著再將第四個元素加入,重覆此步驟,直到排 序完成為止。 可以看做是在一串有序的記錄R1、R2…Ri,插入 新的記錄R,使得i+1個記錄排序妥當。 20 7-2 內部排序法 以下我們利用55、23、87、62、16數列的由小到 大排序過程,來說明插入排序法的演算流程。 下圖中,在步驟二,以23為基準與其他元素比較 後,放到適當位置(55的前面),步驟三則拿87與 其他兩個元素比較,接著62在比較完前三個數後 插入87的前面…將最後一個元素比較完後即完成 排序: 21 7-2 內部排序法 插入法分析 1.最壞及平均清況需比較(n-1)+(n-2)+(n-3)+…+3+2+1= 次;時間複雜度為O(n2),最好情況時間複雜度為 :O(n) 2.插入排序是穩定排序法。 3.只需一個額外的空間,所以空間複雜度為最佳。 4.此排序法適用於大部份資料已經過排序或已排序資料 庫新增資料後進行排序。 5.插入排序法會造成資料的大量搬移,所以建議在鏈結 串列上使用。 22 7-2 內部排序法 範例 7.2.5 請設計一Java程式,自行輸入6個數值,並使用插 入排序法來加以排序。 23 7-2 內部排序法 謝耳排序法 是D. L. Shell 在1959年7月所發明的一種排序法, 可以減少插入排序法中資料搬移的次數,以加速 排序進行。 排序的原則是將資料區分成特定間隔的幾個小區 塊,以插入排序法排完區塊內的資料後再漸漸減 少間隔的距離。 以下我們仍然利用63、92、27、36、45、71、58、 7數列的由小到大排序過程,來說明插入排序法的 演算流程: 24 7-2 內部排序法 • 首先將所有資料分成Y:(8div2)即Y=4,稱為劃分數。 請注意!劃分數不一定要是2,質數是最好。但為演算 法方便,所以我們習慣選2。則一開始的間隔設定為 8/2區隔成: • 如此一來可得到四個區塊分別是: (6.4)(9.7)(2.5)(3.1)再各別用插入排序法排序成為: (4.6)(7.9)(2.5)(1.3) • 接著再縮小間隔為(8/2)/2成 25 7-2 內部排序法 • (4.2.6.5)(7.1.9.3)分別用插入排序法後得到: • 最後再以((8/2)/2)/2的間距做插入排序,也就是每一 個元素進行排序得到最後的結果: 謝耳法分析 1.任何情況的時間複雜度均為O(n3/2)。 2.謝耳排序法和插入排序法一樣,都是穩定排序。 3.只需一個額外空間,所以空間複雜度是最佳。 4.此排序法適用於資料大部份都已排序完成的情況。 26 7-2 內部排序法 範例 7.2.6 請設計一Java程式,自行輸入8個數值,並使用謝 耳排序法來加以排序。 27 7-2 內部排序法 合併排序法 通常是外部儲存裝置最常用的排序方法,工作原 理乃是針對已排序好的二個或二個以上的檔案, 經由合併的方式,將其組合成一個大的且已排序 好的檔案。步驟如下: 1.將N個長度為1的鍵值成對地合併成N/2個長度為2的鍵 值組。 2.將N/2個長度為2的鍵值組成對地合併成N/4個長度為4 的鍵值組。 3.將鍵值組不斷地合併,直到合併成一組長度為N的鍵 值組為止。 28 7-2 內部排序法 合併排序法的基本演算流程 以條列的方式將步驟整理如下: 1.將N個長度為1的檔案合併成N/2個已排序妥當且長度為2 的檔案。 2.將N/2個長度為2的檔案合併成N/4個已排序妥當且長度為 4的檔案。 3.將N/4個長度為4的檔案合併成N/8個已排序妥當且長度為 8的檔案。 4.將N/2i-1個長度為2i-1的檔案合併成N/2i個已排序妥當且長 度為2i的檔案。 29 7-2 內部排序法 快速排序法 又稱分割交換排序法,是目前公認最佳的排序法, 也是使用切割征服(Divide and Conquer)的方式, 會先在資料中找到一個隨機會自行設定一個虛擬 中間值,並依此中間值將所有打算排序的資料分 為兩部份。 假設有n筆R1、R2、R3…Rn記錄,其鍵值為k1、k2、 k3…kn: ①先假設K的值為第一個鍵值。 ②由左向右找出鍵值Ki,使得Ki>K。 ③由右向左找出鍵值Kj使得Kj<K。 ④如果i<j,那麼Ki與Kj互換,並回到步驟②。 ⑤若i≧j則將K與Kj交換,並以j為基準點分割成左右部份。然後再針 對左右兩邊進行步驟①至⑤,直到左半邊鍵值=右半邊鍵值為止。 30 7-2 內部排序法 快速排序法將下列資料的排序過程 因為i<j故交換Ki與Kj,然後繼續比較: 因為i<j故交換Ki與Kj,然後繼續比較: 31 7-2 內部排序法 因為ij故交換K與Kj,並以j為基準點分割成左右 兩半: 由上述這幾個步驟,各位可以將小於鍵值K放在左 半部;大於鍵值K放在右半部,依上述的排序過程, 針對左右兩部份分別排序。過程如下: 32 7-2 內部排序法 快速法分析 1.在最快及平均情況下,時間複雜度為O(nlog2n)。最壞 情況就是每次挑中的中間值不是最大就是最小,其時間 複雜度為O(n2)。 2.快速排序法不是穩定排序法。 3.在最差的情況下,空間複雜度為O(n),而最佳情況為 O(log2n)。 4.快速排序法是平均執行時間最快的排序法。 33 7-2 內部排序法 範例 7.2.7 請設計一Java程式,可輸入陣列的個數,並使用 亂數產生數值,試利用快速排序法加以排序。 34 7-2 內部排序法 堆積排序法 堆積排序法使用到了二元樹的技巧,它是利用堆 積樹來完成排序。堆積是一種特殊的二元樹,可 分為最大堆積樹及最小堆積樹兩種。而最大堆積 樹滿足以下3個條件: 1.它是一個完整二元樹。 2.所有節點的值都大於或等於它左右子節點的值。 3.樹根是堆積樹中最大的。 最小堆積樹則具備以下3個條件: 1.它是一個完整二元樹。 2.所有節點的值都小於或等於它左右子節點的值。 3.樹根是堆積樹中最小的。 35 7-2 內部排序法 範例 將利用堆積排序法針對34、19、40、14、57、17、 4、43的排序過程示範如下 依下圖數字順序建立完整二元樹 36 7-2 內部排序法 建立堆積樹 將57自樹根移除,重新建立堆積樹 將43自樹根移除,重新建立堆積樹 37 7-2 內部排序法 將40自樹根移除,重新建立堆積樹 將34自樹根移除,重新建立堆積樹 將19自樹根移除,重新建立堆積樹 38 7-2 內部排序法 將17自樹根移除,重新建立堆積樹 將14自樹根移除,重新建立堆積樹 最後將4自樹根移除。得到的排序結果為 57、43、40、34、19、17、14、4 堆積法分析 1.在所有情況下,時間複雜度均為O(nlogn)。 2.堆積排序法不是穩定排序法。 3.只需要一額外的空間,空間複雜度為O(1)。 39 7-2 內部排序法 範例 7.2.8 請設計一Java程式,並使用堆積排序法來將一數 列排序。 40 7-2 內部排序法 基數排序法 基數排序法依比較的方向可分為最有效鍵優先 (Most Significant Digit First:MSD)和最無效 鍵優先(Least Significant Digit First:LSD)兩 種。 底下的範例以LSD將三位數的整數資料來加以排序, 它是依個位數、十位數、百位數來進行排序。以 下最無效鍵優先(LSD)例子的說明,便可清楚的知 道它的動作原理: 原始資料: 41 7-2 內部排序法 • 步驟一:把每個整數依其個位數字放到串列中 • 合併後成為 • 步驟二:再依其十位數字,依序放到串列中: • 合併後成為 42 7-2 內部排序法 • 步驟三:再依其百位數字,依序放到串列中 • 最後合併即完成排序 43 7-2 內部排序法 範例 7.2.9 請設計一Java程式,可自行輸入數值陣列的個數, 並使用基數排序法來排序。 44 7-3外部排序法 直接合併排序法 直接合併排序法(Direct Merge Sort)是外部儲存 裝置最常用的排序方法。它可以分為兩個步驟: 1.將欲排序的檔案分為幾個可以載入記憶體空間大小的小檔案, 再使用內部排序法將各檔案內的資料排序。 2.將第一步驟所建立的小檔案每二個合併成一個檔案。兩兩合併後 ,把所有檔案合併成一個檔案後就可以完成排序了。 例如:把一個檔案分成6個小檔案: 45 7-3外部排序法 小檔案都完成排序後,兩兩合併成一個較大的檔 案,最後再合併成一個檔案即可完成。 46 7-3外部排序法 範例 7.3.1 請設計一Java程式,直接把兩個已經排序好的檔 案合併與排序成一個檔案。 data1.dat:1 3 4 5 dara2.dat:2 6 7 9 47 7-3外部排序法 範例 7.3.2 請設計一Java程式,利用合併排序法將一檔案拆 成兩個或兩個以上的行程(runs),再利用上一個 範例程式所介紹的方法合併成一個檔案。 48 7-3外部排序法 k路合併法 描述利用3路合併(3-way merge)來處理27個行程 (Runs)的示意圖。 使用k-way合併的原意是希望減少輸出入時間,但 合併k個行程前要決定下一筆輸出的排序資料,必 須作k-1次比較才可以得到答案。 49 7-3外部排序法 多相合併法 下圖共有21個runs,使用2-way合併及3個磁帶T1、 T2、T3來進行合併,假設這21個行程(已排序完畢, 且令其長度為1)的表示方為Sn,其中S為行程大小, n為長度相同run的個數。例如8個runs且長度為2, 可表示成28。 50 7-3外部排序法 使用2-way及3個磁碟的多項合併 51 本章結束 Q&A討論時間 52