250 likes | 447 Views
第十一章 排序. 排序( sort )是電腦科技最常用的一種作業,依資料的值排成指定的順序,通常是由小而大的升冪順序( ascending ),也可以依資料的值排成由大而小的降冪順序( descending ),我們週遭到處都是資料,例如電話簿,電話號碼若不照順序排列,您要找到朋友的電話恐怕很難。. 11.1 排序概念.
E N D
第十一章 排序 • 排序(sort)是電腦科技最常用的一種作業,依資料的值排成指定的順序,通常是由小而大的升冪順序(ascending),也可以依資料的值排成由大而小的降冪順序(descending),我們週遭到處都是資料,例如電話簿,電話號碼若不照順序排列,您要找到朋友的電話恐怕很難。
11.1 排序概念 • 本章將介紹六個內部排序(internal sort)方法:插入(insert)排序法、氣泡(bubble)排序法、選擇(selection)排序法、謝耳(shell)排序法、堆積(heap)排序法、以及快速(quick)排序法,前三種只用於小量的資料,但卻是後三種排序法的基礎,也是一般排序法的基本觀念。 • 我們將利用內部排序的基本觀念發展成外部排序(external sort)的合併排序法(merge sort)。 • 所謂內部排序是指在電腦的記憶體裡頭排序的,但當檔案記錄非常龐大,以致電腦的記憶體無法容納時,必須有部份的檔案記錄儲存在媒體上,部份排序後分配至多個檔案,然後從多個檔案合併成一個檔案,重複排序合併的動作,直到全部排序完成為止。
穩定性是否良好 • 排序的方法有許多種,要注意穩定性是否良好,例如下列的資料依編號排序,編號同為 222 的有三筆資料,排序後會聚集在一起。 • ... ... ... • 222 red 222 red 222 red • ... 222 green 222 blue • 222 green 222 blue 222 green • ... ... ... • 222 blue ... ... • (a)未排序 (b)穩定性佳 (c)穩定性差 • 第(b)種情形依原來的前後順序排列,穩定性佳。第(c)種情形並不依原來的前後順序排列,穩定性差。在前面標明的六種排序法裡頭只有直接插入法及氣泡法屬於穩定性佳的排序法,其他的排序法穩定性不佳。
排序的效率 • 排序的效率也是使用時要考慮的因素,效率通常與比較的次數以及資料搬移的多寡及次數都有關係,一般而言,效率與 nlogn 成比例的最佳,n 表資料量,快速排序法就屬於這一種。其他幾種其效率都與 n 的平方成正比。 • 當排序處理當中,資料來回傳送許多次,從頭到尾處理一遍稱為一回(pass),依演算法的不同其回數也不同。
11.2 選擇排序 • 在所有排序法當中,選擇排序可說最直覺的了。若提供一系列的資料,我們一定很單純的選擇最小的擺在排序完成系列的第一位,再從剩下的資料再選擇最小的擺在排序完成系列的第二位,如此重複,直到沒有資料為止。我們將介紹兩種選擇排序法:直接選擇排序以及堆積選擇排序。
11.2.1 直接選擇排序 • 直接選擇排序在任何時刻,資料串列(data list)都被分成兩個次串列(sublist):未排序以及已排序次串列。我們從未排序次串列裡頭選出最小的與第一個資料互換,如此選擇互換一回後,第一個資料就屬於已排序次串列,其餘的資料屬於未排序次串列。再從未排序次串列裡頭選出最小的與第一個資料互換一回,如此選擇互換後,第二個資料就屬於已排序次串列,其餘的資料屬於未排序次串列。選擇互換的動作一直重複,這個無形的分隔線一直往右邊移動,已排序次串列一直擴大,未排序次串列一直縮小,一直到沒有未排序次串列為止。
11.2.2 堆積排序法 • 堆積(heap)是一個二元樹(binary tree)結構,其左右子樹之值均小於其父母(parent)節點之值,一個堆積根節點(root node)是全樹所有節點中最大值的節點。堆積通常以陣列實作,而非以連結串列實作。以陣列實作的優點是容易計算子樹節點的位置,也容易計算父母節點的位置,增加處理的效率。
一棵二元樹 上圖是一個八個元素的 k 陣列,k[0] 第零個元素不用,以一個二元樹表示,因為根節點的值並非最大者,因此不構成一個堆積。
註標i=3的子樹 因為 44 並非最大值,與子樹 55 與 18 中較大者互換,新 k[3] 子樹根節點值 55 是該子樹最大值,已成堆積。
註標i=2的子樹 將原來 i=3 減一,即 i=2,k[i]=77,該根節點值 77 是該子樹最大值,原已成堆積,不必互換。
註標i=1的樹 將原來 i=2 減一,即 i=1,k[i]=22 並非該樹中最大值者,將根節點值 22 先保存至另一變數 kk,即 kk=k[i]=22,然後將其子樹中較大者其節點值 77 上升,取代根節點 22,成為新的根節點,77 上升後其位置就空下來了,如下圖所示。
77上升後其位置就空下來了 這時將 i 往下降一層,讓 i=j=2,新的 j=2*i=4,j+1=5,將 k[j]=k[4] 與 k[j+1]=k[5] 中的較大者 31 上升至空位,如下圖所示。
31上升後其位置就空下來了 這時第 j+1=5 節點已是葉節點(leaf)了,才將保存於 kk 原來根節點的值 22 置入,即 k[j+1]=k[5]=22,變成如下圖的堆積樹。
根節點值 77 已是全樹裡最大的值 • 將原來資料做適當的選擇互換後所建立的堆積樹只是堆積排序的前半段工作而已,因為根節點值 77 已是全樹裡最大的值,只須將它輸出存入一個暫時變數 kk,即 kk=77,然後從子樹較大值上升至根節點,子樹一層一層下降,較大值上升至子樹根節點,最後有一個葉節點空下來,就將最右邊的 R 位置值置入此空位置,然後讓 k[R]=kk,第一回合時 R=N=7,就完成一回合了,如下兩圖所示。
第六回合做完後之二元樹及陣列 第六回合後只剩下一個根節點,無從比較,完成了堆積排序,只須依序輸出 k[1]、k[2]、...、k[N] 就可得到結果。
編譯執行 • ch11> gcc heapsort.c -o heapsort.exe <Enter> • ch11> heapsort.exe <Enter> • heap sort • 1 2 3 4 5 6 7 L R kk • ---- ---- ---- ---- ---- ---- ---- -------- • 22 77 55 7 31 44 18 3 7 44 • 22 77 55 7 31 44 18 2 7 77 • 77 31 55 7 22 44 18 1 7 22 • 55 31 44 7 22 18 77 1 6 18 • 44 31 18 7 22 55 77 1 5 18 • 31 22 18 7 44 55 77 1 4 22 • 22 7 18 31 44 55 77 1 3 7 • 18 7 22 31 44 55 77 1 2 18 • 7 18 22 31 44 55 77 1 1 7