210 likes | 299 Views
11.3 插入排序. 插入排序( insertion sorting )是以前使用卡片儲存資料時代最常使用的排序方法,使用者挑出一張卡片,決定它的位置,就插入適當的位置,同樣的方式也適用於程式,在插入排序處理的一個回合裡,會插入一個記錄進入已排序完成的串列裡頭。 本小節將介紹兩種插入排序方法:直接插入以及謝耳( shell )排序法。. 11.3.1 直接插入排序.
E N D
11.3 插入排序 • 插入排序(insertion sorting)是以前使用卡片儲存資料時代最常使用的排序方法,使用者挑出一張卡片,決定它的位置,就插入適當的位置,同樣的方式也適用於程式,在插入排序處理的一個回合裡,會插入一個記錄進入已排序完成的串列裡頭。 • 本小節將介紹兩種插入排序方法:直接插入以及謝耳(shell)排序法。
11.3.1 直接插入排序 • 在直接插入排序法(direct insertion sort)裡,資料串列分成兩個部份:已排序及未排序次串列。在每一個排序回合裡,未排序次串列裡第一項資料移動至已排序次串列裡的適當位置。若有 n 項資料,最多需要 n-1 次的排序回合。
直接插入排序函式 • 直接插入排序函式原型宣告如下: • void insertSort(int k[], int L, int R) • 需要三個引數,陣列 k[],左範圍註標 L,右範圍註標 R。 • 先將標的元素存入 kk,其後的元素逐一與 kk 比較,若較 kk 大則搬移至右一位,空出本身位置,直到較 kk 小時,就找到 kk 的位置,置入 kk 值。
編譯執行 • ch11> gcc insertsort.c -o insertsort.exe <Enter> • ch11> insertsort.exe <Enter> • 7 22 31 44 55 77
11.3.2 謝耳排序 • 謝耳排序法(Shell sort)是記念創造者 Donald L. Shell 先生,是一款直接插入排序法的改良版本,也是屬於快速排序法。 • 謝耳排序法將 N 個資料分割成 M 個分段(segment),每一個分段包含 N/M 個資料,若不能整除則每一段資料個數會有不同。 • 若 N=8,M=3 則分段如下: • k[0] k[1] k[2] k[3] k[4] k[5] k[6] k[7] • 第一段包含 k[0]、k[3]、k[6],第二段包含 k[1]、k[4]、k[7],第三段包含 k[2]、k[5]。
謝耳排序分M段 • 若 N=8,M=2 則分段如下: • k[0] k[1] k[2] k[3] k[4] k[5] k[6] k[7] • 第一段包含 k[0]、k[2]、k[4]、k[6],第二段包含 k[1]、k[3]、k[5],k[7]。 • 若 N=8,M=1 則分段如下: • k[0] k[1] k[2] k[3] k[4] k[5] k[6] k[7] • 第一段包含 k[0]、k[1]、k[2]、k[3]、k[4]、k[5]、k[6]、k[7],且是惟一的一段。
謝耳排序 • 謝耳排序函式原型宣告如下: • void shellSort(int k[], int L, int R) • 需要三個引數,陣列 k[],左範圍註標 L,右範圍註標 R。 • 首先設 m=(R-L+1)/2=(7-0+1)/2=4,分成四段,第一段 k[0]、k[4] ,第二段 k[1]、k[5],第三段 k[2]、k[6],第四段 k[3]、k[7],各段分別以插入排序法排序,稱為第一回合。 • 然後設定 m=m/2=2,分為兩段,第一段 k[0]、k[2]、k[4]、k[6],第二段 k[1]、k[3],k[5]、k[7],各段分別以插入排序法排序,稱為第二回合。 • 然後設定 m=m/2=1,分為一段 k[0]、k[1]、k[2]、k[3]、k41]、k[5],k[6]、k[7],以插入排序法排序,稱為第三回合,完成排序。
編譯執行 • ch11> gcc shellsort.c -o shellsort.exe <Enter> • ch11> shellsort.exe <Enter> • Original array : • 76 61 13 8 29 20 79 24 • m=4 • 29 20 13 8 76 61 79 24 • m=2 • 13 8 29 20 76 24 79 61 • m=1 • 8 13 20 24 29 61 76 79 • After shell sort : • 8 13 20 24 29 61 76 79
11.4 互換排序 • 排序的第三類別屬於互換排序(exchange),本小節說明氣泡排序法(bubble sort)以及快速排序法(quick sort)。
11.4.1 氣泡排序 • 氣泡排序在任何時刻,資料串列都被分成兩個次串列:未排序以及已排序次串列。我們從未排序次串列裡頭鄰近兩個資料比較,不合指定順序者互換其值,從右往左逐一比較互換。 • 如此選擇互換後,屬於已排序次串列逐漸擴展,而屬於未排序次串列之範圍逐漸縮小,比較互換的動作一直重複,一直到沒有未排序次串列為止。
上圖是六個資料項 k[] 陣列的氣泡排序法,逐一從右往左比較互換。 • 1. k[5] 與 k[4] 比較,52 比 73 小, • 互換,k[5]=73,k[4]=52。 • 2. k[4] 與 k[3] 比較,52 較 15 大, • 已合乎右大左小的順序,因此不互換。 • 3. k[3] 與 k[2] 比較,15 較 41 小, • 互換,k[3]=41,k[2]=15。 • 4. k[2] 與 k[1] 比較,15 較 78 小, • 互換,k[2]=78,k[1]=15。 • 5. k[1] 與 k[0] 比較,15 較 12 大,不互換。 • 這五個動作稱為第一回合,原資料變更如下: • [0] [1] [2] [3] [4] [5] • ----- ----- ----- ----- ----- ----- • 12 15 78 41 52 73
編譯執行 • ch11> gcc bubblesort.c -o bubblesort.exe <Enter> • ch11> bubblesort.exe <Enter> • Original array : • 12 78 41 15 73 52 • Start bubble sort : • pass #1 • 12 15 78 41 52 73 • pass #2 • 12 15 41 78 52 73 • pass #3 • 12 15 41 52 78 73 • pass #4 • 12 15 41 52 73 78 • After bubble sort : • 12 15 41 52 73 78
11.4.2 快速排序 • 在氣泡排序時,比較相鄰的兩項再決定是否互換資料,互換資料的次數相當頻繁,因而降低排序的速度。 • 快速排序也屬於互換排序,它是公元一九六二年由 C.A.R.Hoare 所發展出來的演算法,它較氣泡排序快速,因其互換資料次數較少,因此排序速度較快。 • 快速排序每一次從陣列裡選出一個元素當基準(pivot),該基準也稱為標竿(pole),將陣列元素分為三群:標竿左群、標竿、標竿右群。讓標竿左群所有元素值均比標竿值小,讓標竿右群所有元素值均大於或等於標竿值,如此標竿就處於正確位置了。 • 標竿左群元素個數若小於或等於指定的數量,例如 MINSIZE=8,就直接使用插入法排序,元素個數若大於指定的數量,就繼續快速排序。標竿右群也做同樣的處理。
找出pivot標竿元素 第一個目標要找出標竿元素。若左邊的值 k[L] 大於 k[M] 中間的值,則其值互換。若左邊的值 k[L] 大於 k[R] 右邊的值,則其值互換。若中間的值 k[M] 大於 k[R] 右邊的值,則其值互換。然後左邊值與中間值互換,這時左邊值就是基準的標竿了。如下圖所示。
標竿63的正確位置 第二個目標要決定標竿元素的正確位置。從標竿右邊的元素 22 開始,往右找尋大於或等於標竿的元素,找到 98,其位置為 i=4。接著從右邊界 R 元素開始,往左找尋比標竿小的元素,找到 46,其位置為 j=10,這兩個元素互換。
快速排序完成 標竿左群含四個元素,分別為 {k[1],...,k[4]},其值分別為 {23,22,15,46},其個數 4 小於 MINSIZE(8),因此直接插入排序成 {15,22,23,46}。標竿右群含七個元素,分別為 {k[6],...,k[12]},其值分別為 {88,75,86,77,98,85,79},其個數 7 小於 MINSIZE(8),因此直接插入排序成 {75,77,79,85,86,88,98}。
編譯執行 • ch11> gcc quicksort.c -o quicksort.exe <Enter> • ch11> quicksort.exe <Enter> • original k[] array : • 79 22 15 98 88 63 75 86 77 46 85 23 • pivot subscript=5, k[5]=63 • 23 22 15 46 63 88 75 86 77 98 85 79 • k[] array after quickSort() : • 15 22 23 46 63 75 77 79 85 86 88 98