算法的穩定性:若是待排序的兩個元素Ri,Rj,其對應的關鍵字keyi=keyj,且在排序前Ri在Rj的前面,若是排序後Ri還在Rj的前面,則稱這種排序算法是穩定的,不然稱排序算法是不穩定的。node
內部排序和外部排序:內部排序是指在排序期間,元素所有存放在內存中的排序。外部排序是指排序期間元素沒法所有同時存放在內存中,必須在排序過程當中根據要求不斷地在內外存之間移動的排序。算法
1.插入排序數組
1)插入排序:每次將一個待排序的記錄,按其關鍵字大小插入到前面已經排好序的子序列中,直到所有記錄插入完成。app
時間複雜度:O(n2),空間複雜度:O(1).穩定性:穩定的排序方法。函數
2)希爾排序:將待排序表分割成若個形如L[i,i+d,i+2d,i+3d,.....i+kd]的特殊子表,分別進行直接插入排序。當整個表呈基本有序時,在對全體記錄進行一次直接插入排序。性能
過程:先去一個小於n的步長d1,把表中所有記錄分紅d1個組,全部距離爲d1的倍數的記錄放在同一組中,在各組中進行直接插入排序。而後取第二個步長d2<d1.重複上述過程,直到di=1,即全部記錄在同一組中,再進行直接插入排序。測試
增量求法:目前不統一,通常採用d1=n/2,,ui
時間複雜度:當n在某個特定範圍時爲spa
不穩定排序3d
2.交換排序
冒泡排序:將設待排序表長爲n,從後往前兩兩比較相鄰元素的值,若爲逆序,則交換他們,直到序列比較完。此爲一趟冒泡。結果爲將最小的元素交換到待排序的第一個位置。下一趟冒泡時,前一趟肯定的最小元素再也不參與比較,待排序列減小一個元素,每趟排序吧最小元素放到最終位置,這樣最多作n-1趟冒泡就把全部元素排好。
過程:首先假定劃分算法已知,記爲partition(),返回上述中的k,L(k)已經在最終位置上,因此能夠先對錶進行劃分,然後對錶調用一樣的排序操做。遞歸的調用快速排序算法進行排序。程序結構以下:
1)兩個下標分別從首,尾向中間掃描的方法
假設每次都是以當前表中第一個元素做爲樞紐值對錶進行劃分,則必須將表中比樞紐值大的元素向右移動,比樞紐值小的元素向左移動,使得一趟partition()操做後,表的元素被樞紐值一分爲二。
若初始序列3,8,7,1,2,5,6,4排序過程以下:
2 8 7 1 2 5 6 4
2 8 7 1 8 5 6 4
2 1 7 1 8 5 6 4
2 1 7 7 8 5 6 4
2 1 3 7 8 5 6 4 //A[high]A[low]
2)兩個指針索引一前一後逐步向後掃描
快速排序是全部內部排序算法中平均性能最優的排序算法。在快速排序算法中,並不產生有序子序列,但每一趟排序後將一個元素(基準元素)放在其最終位置上。當初始排序表基本有序或基本逆序是,就獲得最壞狀況下的時間複雜度O(n2).
A快排一次排序的應用
A)區分數組中大小寫字母(編寫函數,讓小寫字母在全部大寫字母以前)
b)給定含n個元素的整型數組a,包含0和非0,對數組進行排序,使排序後知足1.排序後的全部0元素在前,非零元素在後,且非零元素排序先後相對位置不變,不能使用額外的存儲空間。
c)荷蘭國旗問題
D)輸入n個整數,輸出其中最小的k個。
思路1:將輸入的n個數排序,這樣排在最前面的k個數就是最小的k個數。
思路2:假設最小的k個數中最大的爲A。在快排中,先在數組中隨機選擇一個數字,而後調整數組中數字的順序,使得比選中數字小的數字排在他的左邊,比選中數字大的排在他的右邊(快排一次)
若選中的數字下表恰好是k-1(從0開始),那麼這個數字(A)加上左側的k-1個數就是最小的k個數。若是他的小標大於k-1,則A位於他的左側,咱們能夠在他的左邊部分的數組中查找。若小標小於k-1,那麼A應該位於他的右邊,咱們能夠接着在他的右邊部分中尋找。(發現這是一個遞歸問題,可是咱們找到的k個數不必定是有序的)
3.選擇排序
思想:每一趟在後面n-i+1(i=1,2..n-1)個待排序元素中選取關鍵字最小的元素,做爲有序子序列的第i個元素,直到n-1趟作完,待排序元素只剩下1就不用再選了。
1)簡單選擇排序
空間複雜度:O(1)。時間複雜度:元素移動較少不超過3(n-1)(一次swap三次元素移動)。最好移動0次(此時表已經有序)。可是元素間比較的次數與序列的初始狀態無關,始終爲n(n-1)/2次。時間複雜度爲O(n2).
2)堆排序
堆排序是一種樹形選擇排序方法,在排序過程當中將L[1..n]視爲一棵徹底二叉樹的順序村粗結構。利用徹底二叉樹中雙親結點和孩子結點之間的內在關係,在當前無序區中選擇關鍵字最大(或最小)的元素。
堆排序的實質是構建初始堆,對初始序列建堆,就是一個反覆篩選的過程。
A)根據初始關鍵字序列(20,18,22,16,30,19)構建初始大根堆。
在元素個數爲n的序列上建堆,其時間複雜度爲O(n),這說明能夠在線性時間內,將一個無序數組建成一個大頂堆。
B)堆排序的思想
因爲堆自己的特色(以大頂堆爲例),堆頂元素就是最大值。輸出堆頂元素後,一般將堆底元素放入堆頂,此時根節點已不知足堆的性質,將堆頂元素向下調整繼續保持大頂堆性質,輸出堆頂元素,重複,直到僅剩一個元素爲止。
C)堆的插入和刪除
刪除堆頂元素時,先將堆的最後一個元素與堆頂元素交換,有序性質破壞,須要堆根結點進行向下調整。
對堆進行插入操做時,先將新結點放在堆的末端,再對這個新結點執行向上調整操做,大頂堆插入操做以下圖所示:
向上調整算法以下所示:
D)堆排序的應用(最小k個數)
輸入n個整數,輸出其中最小的k個.(用堆排序來解決,適合處理海量數據)
思路:首先讀入k個數建立一個大小爲k的大頂堆,而後依此讀入剩餘數據,若是當前數據比大頂堆的堆頂小,則用這個數代替當前堆頂元素,並調整時期保持大頂堆性質,若是當前數據比堆頂大,則此數不可能爲最小的k個整數之一,故拋棄此數。(時間複雜度:O(nlogk))
4.歸併排序
含義:將兩個或兩個以上的有序表組合成一個新的有序表。假定待排序表含有n個記錄,則可視爲n個有序子表,每一個子表長度爲1,兩兩歸併,獲得
過程:分解:將n個元素的待排序表分紅各含n/2個元素的子表,採用二路歸併算法對兩個子表遞歸的進行排序。
合併:合併兩個已排序的子表獲得排序結果。
Merge()的功能時將先後相鄰的兩個有序表歸併爲一個有序表的算法。設兩段有序表A【low...mid】A[mid+1...high]存放在同一順序表中相鄰的位置上,先將他們複製到輔助數組B中,每次從對應B中的兩個段取出一個記錄進行關鍵字比較,將較小者放入A中,當輸入B中有一段超出其表長,則將另外一段剩餘部分直接複製到A中。
A)合併兩個排好序的鏈表(連個遞增排序鏈表,合併他們使新鏈表結點仍然是按照遞增排序的)
b)給定有序數組a,b.已知數組a末尾有足夠空間容納b,請實現將b合併到a中。函數頭以下:
Void merge(int a[],int b[],int n,int m)//n爲數組a的元素個數,m爲數組b的元素個數
思路:先計算總元素個數,從數組末尾(最大元素)開始歸併。
C)原地歸併排序(二叉歸併排序 內部排序,不適用輔助空間)
原地歸併排序不須要輔助數組便可歸併。關鍵在merge這個函數。假設有兩段遞增的子數組arr[begin....mid-1]和arr[mid...end],但整個數組不是遞增的。其中i=begin,j=mid,k=end.
而後把i到mid-1的部分和mid到j-1的部分對調(可經過三次逆序實現)較小部分就調到前面去了,此時數組變爲0 1 2 3 4 5 6 9 7 8(前面有序了,後面又是兩個遞增子數組,繼續迭代便可)
D)多路歸併排序(外部排序)
外部排序是指大文件的排序,即待排序的記錄存儲在外部存儲器上,待排序的文件沒法一次裝入內存,須要在內存和外部存儲器之間進行屢次數據交換,以達到排序整個文件的目的。
思路:外部排序最經常使用的算法是多路歸併排序,即將源文件分解成多個可以一次性裝入內存的部分,分別把每一部分調入內存完成排序,而後對已排序的子文件進行歸併排序。
從二路到多路,增大k能夠減小外存信息讀寫時間,但k個歸併段中選擇最小的記錄須要比較k-1次,爲了下降選出每一個記錄須要的比較次數k,引入敗者數。
敗者樹可視爲一棵徹底二叉樹,每一個葉結點存放各歸併段在歸併過程當中當前參加比較的記錄,內部結點用來記憶左右子樹中的失敗者,讓勝者網上繼續進行比較,一直到根節點。若是比較兩個數,大的爲失敗者,小的爲勝利者,則根節點指向的數爲最小數。
圖中第一個葉子結點爲b0.k路歸併的敗者樹深度爲
案例:有20個有序數組,每一個數組有500個unsigned int元素,降序排序。要求從這10000個元素中選出最大的500ge.
思路:依此從20個有序數組中選擇一個當前元素,兩兩比較,而後找出最大的數,循環500次,便可選擇出500個最大的數。可是這裏每選擇一個最大元素,須要比較19次,效率低。
改進方法1:利用堆,從20個數組中各取一個數,並記錄每一個數的來源數組,創建一個含有20個元素的大頂堆。此時堆頂就是最大元素,去除堆頂元素,並從堆頂元素的來源數組中取下一個元素加入堆,調整堆後再取最大值,一直這樣進行500次便可。時間複雜度
改進方法2:利用敗者樹。從20個數組中各取一個數,並記錄每一個數的來源數組,創建一個20路歸併的敗者樹。此時敗者樹輸出的就是最大的數,而後從最大數的來源數組繼續取下一個數加入敗者樹,繼續比較,直到輸出500個數爲止。時間複雜度爲
不一樣排序算法的比較
總結:
1.比較次數和初始排列無關的是選擇排序。
2.在初始序列基本有序的狀況下,最優的是插入排序,此時插入排序時間複雜度爲O(n),其次是冒泡排序,時間複雜度也爲O(n).快速排序此時性能最差,時間複雜度爲
3.堆排序對初始數據集的排列順序不敏感,在最好,最壞和平均狀況下,堆排序的時間複雜度爲
4.節儉排序,一對數字不進行兩次或兩次以上的比較。包括(插入排序,歸併排序)
5.基於比較的排序算法時間複雜度的下界(最好的時間複雜度)爲: