数据结构(7)—— 排序总结
『知識(shí)框架』
?
「排序基本概念 」
算法的穩(wěn)定性:若待排序中有兩個(gè)元素 和 ,對(duì)應(yīng)關(guān)鍵字 ? 和 ,且排序前 在 前面,使用某一算法之后, 仍在 之前,則稱排序算法穩(wěn)定。穩(wěn)定性不能衡量一個(gè)算法的優(yōu)劣。
排序算法分類:
- 內(nèi)部排序:排序期間元素全部存在內(nèi)存中的排序
- 外部排序:元素?zé)o法全部放在內(nèi)存中,要在內(nèi)、外存之間移動(dòng)的排序
并非所有排序基于比較操作,比如基數(shù)排序
?
「插入排序 」
?
基本思想:將一個(gè)待排序的記錄按關(guān)鍵字大小插入到已經(jīng)排好序的子序列中,直到全部記錄插入完成
「直接插入排序」
- 查L(i)在L[1...i-1]中的插入位置k
- 將L[k...i-1]中所有元素全部后移一個(gè)位置
- 將L(i) 復(fù)制到 L(k)
上述過程執(zhí)行n-1次得到一個(gè)有序表,空間復(fù)雜度O(1),最好情況表元素已有序,只比較一次不移動(dòng),時(shí)間復(fù)雜度O(n);最壞情況逆序,總比較次數(shù) n(n-1)/2,移動(dòng)次數(shù)也達(dá)到了最大,復(fù)雜度O(n^2)
直接插入排序穩(wěn)定,適合順序存儲(chǔ)和鏈?zhǔn)酱宕?#xff0c;大部分排序算法適合順序存儲(chǔ)的線性表。
「折半插入排序」
在查找插入位置時(shí)使用折半查找來實(shí)現(xiàn)。折半插入減少了比較次數(shù),約為O(),比較次數(shù)與待排表的初始狀態(tài)無關(guān),僅取決于元素個(gè)數(shù)n;元素移動(dòng)次數(shù)不改變。因此,折半插入復(fù)雜度O(n^2)。是一種穩(wěn)定排序方法
「希爾排序」
將排序表分成L[i,i+d,i+2d....i+kd]的特殊字表,分別進(jìn)行直接插入排序,當(dāng)整個(gè)表已經(jīng)基本有序時(shí),再對(duì)全體進(jìn)行一次直接插入排序。取一個(gè)d,分成d組,距離為d的倍數(shù)的記錄放在同一組。然后排序;再取d,重復(fù),直到d=1。
時(shí)間復(fù)雜度O(1),最壞情況O(n^2),n在某范圍O(n^1.3)
算法不穩(wěn)定
?
「交換排序 」
交換:根據(jù)系列中兩個(gè)元素關(guān)鍵字的比較結(jié)果兌換這兩個(gè)記錄在序列中的位置
「冒泡排序」
思想:待排表長n,從后往前兩兩比較相鄰元素值,若為逆序,交換,直到序列比較完,最小的元素排在第一個(gè)位置,稱一趟排序。在之后的冒泡過程中,排好的元素不參與比較。最多做n-1趟冒泡。
初始有序,比較n-1次,移動(dòng)0次,最好復(fù)雜度O(n);
初始逆序,n-1趟排序,第i趟進(jìn)行n-i次比較,比較次數(shù) n(n-1)/2,移動(dòng)次數(shù)3n(n-1)/2,所以最壞O(n^2),平均也O(n^2)
算法穩(wěn)定,冒泡排序中所產(chǎn)生的有序子序列一定全局有序,每趟排序都會(huì)將一個(gè)元素放到最終的位置上。
「快速排序」
思想:基于分治,在待排表中選一個(gè)作為基準(zhǔn),通過一趟把表劃分成兩部分,前半部分小于基準(zhǔn),后半部分大于等于基準(zhǔn)值,稱一趟快排。而后遞歸重復(fù)上述過程,直至每個(gè)部分只有一個(gè)元素或空為止。
快排性能取決于劃分操作的好壞。
空間效率:快排是遞歸的,最好情況 ,最壞O(n),平均O()
時(shí)間效率:最壞O(n^2),一般為O()
快排是所有內(nèi)部排序算法中性能最優(yōu)的排序算法
快排不穩(wěn)定,每趟排序都會(huì)將一個(gè)元素放到最終的位置上。
?
「選擇排序 」
「簡(jiǎn)單選擇排序」
思想:假設(shè)表L[1...n],第i趟排序從L[i...n]中選擇關(guān)鍵字最小的元素與L(i)交換,經(jīng)過n-1趟確定最終排序結(jié)果。
簡(jiǎn)單選擇排序,移動(dòng)操作次數(shù)很少;元素間比較的次數(shù)與序列的初始狀態(tài)無關(guān),始終 n(n-1)/2次,復(fù)雜度O(n^2)
算法不穩(wěn)定,每趟排序會(huì)將一個(gè)元素放到最終的位置上
「堆排序」
思想:樹形選擇排序方法,視為一棵完全二叉樹的順序存儲(chǔ)結(jié)構(gòu),利用雙親和孩子結(jié)點(diǎn)的關(guān)系,選擇元素排序。
建堆后,n-1次向下調(diào)整,時(shí)間與樹高有關(guān),為O(h)
在元素個(gè)數(shù)為n的序列上建堆,時(shí)間復(fù)雜度O(n)
算法不穩(wěn)定。?
「歸并排序和基數(shù)排序 」
「歸并排序」
歸并:將兩個(gè)或兩個(gè)以上的有序表組合成一個(gè)新的有序表。
思想:設(shè)有兩段有序表A[low,mid]、A[mid+1,high]存在同一順序表中的相鄰位置,先復(fù)制到輔助數(shù)組B中。每次從對(duì)應(yīng)B中兩個(gè)段取出一個(gè)記錄進(jìn)行關(guān)鍵字的比較,將較小者放入A,當(dāng)數(shù)組B中有一段的下標(biāo)超出其對(duì)應(yīng)的表長時(shí),將另一段剩余部分直接復(fù)制到A中。
遞歸形式的2路歸并排序算法基于分治。
空間效率:O(n)
時(shí)間效率:每趟歸并時(shí)間復(fù)雜度O(n),共需進(jìn)行 趟歸并,算法時(shí)間復(fù)雜度O()
算法穩(wěn)定
「基數(shù)排序」
基數(shù)排序不基于比較,借助“分配”和“收集”對(duì)關(guān)鍵字進(jìn)行排序
空間效率:一趟排序需要輔助存儲(chǔ)空間r(r個(gè)隊(duì)列),所以為O(r)
時(shí)間效率:進(jìn)行d趟分配和收集,一趟分配O(n),一趟收集O(r),復(fù)雜度O(d(n+r)),它與序列的初始狀態(tài)無關(guān)
算法穩(wěn)定
?
「內(nèi)部排序算法比較」
| 算法種類 | 時(shí)間復(fù)雜度 | 空間復(fù)雜度 | 是否穩(wěn)定 | ||
| 最好情況 | 最壞情況 | 平均情況 | |||
| 直接插入排序 | YES | ||||
| 冒泡排序 | YES | ||||
| 簡(jiǎn)單選擇排序 | NO | ||||
| 希爾排序 | ? | NO | |||
| 快速排序 | NO | ||||
| 堆排序 | NO | ||||
| 2路歸并排序 | YES | ||||
| 基數(shù)排序 | YES | ||||
?
?
「外部排序算法」
「外部排序的基本概念」
外部排序:需要將待排序記錄存儲(chǔ)在外存上,排序時(shí)再把數(shù)據(jù)一部分一部分地調(diào)用內(nèi)存進(jìn)行排序,排序過程中需要多次進(jìn)行內(nèi)存和外存之間的交換,對(duì)外存文件中的記錄進(jìn)行排序后的結(jié)果仍然放到原有文件中。
外部排序方法通常采用歸并排序方法,包括兩個(gè)獨(dú)立的階段:首先,根據(jù)內(nèi)存緩沖區(qū)的大小,把外存上含n個(gè)記錄的文件分成若干長度為h的子文件,依次讀入內(nèi)存并利用內(nèi)部排序算法進(jìn)行排序,將排序后的結(jié)果寫回外存,稱這些有序子文件為歸并段;然后對(duì)這些歸并段進(jìn)行逐趟歸并。
外部排序的總時(shí)間:內(nèi)部排序的時(shí)間+外存信息讀寫時(shí)間+內(nèi)部歸并所需時(shí)間:
:對(duì)每個(gè)初始?xì)w并段內(nèi)部排序的時(shí)間
:初始?xì)w并段的個(gè)數(shù)
:訪問外存塊的次數(shù)
:每個(gè)塊的存取時(shí)間
:歸并趟數(shù)
:每趟參加2路歸并的記錄個(gè)數(shù)
:每做一次內(nèi)部歸并時(shí),取得一個(gè)關(guān)鍵字最小記錄的時(shí)間
一般的,對(duì)r個(gè)初始?xì)w并段,做m路平衡歸并,歸并樹可用嚴(yán)格的m叉樹表示。歸并趟數(shù) = 樹的高度 = 。可見,只要增大歸并路數(shù)m,或減少初始?xì)w并段的個(gè)數(shù)r,都能減少歸并趟數(shù)S,進(jìn)而減少I/O次數(shù)d,達(dá)到提速的目的。
「多路平衡歸并與敗者樹」
增加歸并路數(shù)m時(shí),內(nèi)部歸并的時(shí)間也會(huì)增加。做內(nèi)部歸并時(shí),在m個(gè)元素中選關(guān)鍵字最小的記錄需要比較m-1次。每趟歸并n個(gè)元素需要 (n-1)(m-1)次比較,S趟歸并需要比較次數(shù):,因此不能使用普通的內(nèi)部歸并排序算法。
為了使內(nèi)部歸并不受m的增大的影響,引入敗者樹。敗者樹可視為一棵完全二叉樹。每個(gè)葉節(jié)點(diǎn)存放各歸并段在歸并過程中當(dāng)前參加比較的記錄,內(nèi)部結(jié)點(diǎn)記錄左右子樹的“失敗者”,讓勝者繼續(xù)比較,一直到根節(jié)點(diǎn)。大的為敗者,小的為勝者,根節(jié)點(diǎn)指向的樹為最小數(shù)。
采用此方法,m路歸并樹的敗者樹深度,從m個(gè)記錄找最小,最多需要次比較,總的比較次數(shù)為:
使用敗者樹后,與m無關(guān),提高了排序速度。但并不是歸并路數(shù)越大越好。歸并路數(shù)m增大時(shí),要增加緩沖區(qū)個(gè)數(shù)。
「置換-選擇排序」
減少初始?xì)w并段的個(gè)數(shù)r也可以減少歸并趟數(shù)S。
設(shè)初始待排文件為FI,初始?xì)w并段文件為FO,內(nèi)存工作區(qū)為WA,內(nèi)存工作區(qū)可容納w個(gè)記錄,置換-選擇算法步驟:
(1)從待排文件FI輸入w個(gè)到WA
(2)從WA中選擇最小的記錄,記為MINMAX
(3)將MINMAX輸出到FO
(4)若FI未讀完,從FI繼續(xù)讀入記錄到WA
(5)從WA中所有比當(dāng)前MINMAX大的關(guān)鍵字中選擇比MINMAX小的記錄,作為新的MINMAX
(6)重復(fù)(3)-(5),直到WA中選不出新的MINMAX為止,由此得到一個(gè)初始?xì)w并段,輸出一個(gè)結(jié)束標(biāo)志到FO中
(7)重復(fù)(2)-(6),直到WA為空。得到所有初始?xì)w并段
選擇MINMAX記錄的過程利用敗者樹實(shí)現(xiàn)
「最佳歸并樹」
文件經(jīng)過置換-選擇,得到長度不等的初始?xì)w并段。如何組織歸并段的歸并順序,使得IO次數(shù)最少呢?
歸并樹中,各葉節(jié)點(diǎn)表示參加歸并的一初始?xì)w并段,葉節(jié)點(diǎn)上權(quán)值表示歸并段的記錄數(shù),根節(jié)點(diǎn)表示最終生成的歸并段,葉節(jié)點(diǎn)到根節(jié)點(diǎn)的路徑長度表示在歸并過程中的歸并趟數(shù),各非葉節(jié)點(diǎn)代表新的歸并片段,則歸并樹的帶權(quán)路徑長WPL即為歸并過程中的總讀記錄數(shù)。為了優(yōu)化WPL,可引入哈夫曼樹的思想推廣到m叉樹。
最佳歸并樹:總IO次數(shù)達(dá)到最少
若初始?xì)w并段不足以構(gòu)成一棵嚴(yán)格m叉樹時(shí),需要添加長度為0的“虛段”,如何確定虛段個(gè)數(shù)?
設(shè)度為0的結(jié)點(diǎn) 個(gè),度為m的結(jié)點(diǎn) 個(gè),對(duì)嚴(yán)格m叉樹 有 ,由此得
- 若,說明正好可以構(gòu)成m叉樹
- 若,有u個(gè)結(jié)點(diǎn)多余,不能包含在m叉樹中。為構(gòu)造包含所有 個(gè)初始?xì)w并段的m叉樹,在原有 個(gè)內(nèi)結(jié)點(diǎn)基礎(chǔ)上增加一個(gè)內(nèi)結(jié)點(diǎn)。在歸并樹中代替一個(gè)葉節(jié)點(diǎn)的位置,被代替的葉節(jié)點(diǎn)加上多出來的u個(gè)結(jié)點(diǎn),再加上m-u-1個(gè)空歸并段,就可建立歸并樹。
?
總結(jié)
以上是生活随笔為你收集整理的数据结构(7)—— 排序总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统(2) -- 进程管理
- 下一篇: 数据仓库与联机分析处理技术