排序是按關鍵字的非遞增或遞減順序對一組記錄中心進行排序的操做。(將一組雜亂無章的數據按必定規律順次排列起來。)算法
未定列表與不穩定列表數據結構
假設 Ki = Kj ( 1 ≤ i ≤ n,1 ≤ j ≤ n,i ≠ j ),在序列前還沒有序列中 Ri 領先於 Rj(即 i < j )。若在排序先後的綠鬣中 Ri 仍大於 Rj ,則稱全部的排序方法爲穩定的,反之爲不穩定。函數
內部排序spa
待排序記錄所有存放在計算機的內存中進行排序的過程。3d
外部排序code
待排序記錄數量很大,以致於內存不能容納所有數據,在排序的時候須要對外存進行訪問的排序過程。blog
時間複雜度排序
關鍵字的比較次數和記錄移動次數。內存
空間複雜度it
執行算法所需的附加存儲空間。
是一種簡單的排序方法,基本操做是將一條記錄插入到已排好序的有序列表中,從而獲得一個新的、記錄數量增一的有序表。
(1)將序列中的第1個記錄當作是一個有序的子序列;
(2)從第2個記錄起逐個進行插入,直至整個序列變成按關鍵字有序序列爲止;
練習: (13,6,3,31,9,27,5,11)
【13】, 6, 3, 31, 9, 27, 5, 11
【6, 13】, 3, 31, 9, 27, 5, 11
【3, 6, 13】, 31, 9, 27, 5, 11
【3, 6, 13,31】, 9, 27, 5, 11
【3, 6, 9, 13,31】, 27, 5, 11
【3, 6, 9, 13,27, 31】, 5, 11
【3, 5, 6, 9, 13,27, 31】, 11
【3, 5, 6, 9, 11,13,27, 31】
void InsertionSort ( SqList &L ) { // 對順序表 L 做直接插入排序。 for ( i=2; i<=L.length; ++i ) if (L.r[i].key < L.r[i-1].key) { L.r[0] = L.r[i]; // 複製爲監視哨 for ( j=i-1; L.r[0].key < L.r[j].key; -- j ) L.r[j+1] = L.r[j]; // 記錄後移 L.r[j+1] = L.r[0]; // 插入到正確位置 } } // InsertSort
時間複雜度 O(n2)
空間複雜度 O(1)
直接插入排序是一種穩定的排序方法。
在插入 r[i] 時,利用折半查找法尋找 r[i] 的插入位置。
void BInsertSort ( SqList &L ) { for ( i = 2; i <= L.length ; ++i ) { L.r[0] = L.r[i]; low = 1 ; high = i-1 ; while ( low <= high ) { m = ( low + high ) / 2 ; if ( L.r[0].key < L.r[m]. key ) high = m -1 ; else low = m + 1; } for ( j=i-1; j>=high+1; - - j ) L.r[j+1] = L.r[j]; L.r[high+1] = L.r[0]; } } // BInsertSort
時間複雜度爲 O(n2)
空間複雜度爲 O(1)
折半插入排序是一種穩定的排序方法
實質上是採用分組插入的方法,將整個待排序記錄序列分割成幾組,從而減小參與直接插入排序的數據量,對每一個分組分別進行直接插入排序,而後增長分組的數據量,從新分組。
子序列的構成不是簡單地「逐段分割」 將相隔某個增量dk的記錄組成一個子序列 讓增量dk逐趟縮短(例如依次取5,3,1) 直到dk=1爲止。
關鍵字序列 T=(49,38,65,97, 76, 13, 27, 49*,55, 04)
void ShellInsert(SqList &L,int dk) { //對順序表L進行一趟增量爲dk的Shell排序,dk爲步長因子 //開始將r[i] 插入有序增量子表 for(i=dk+1;i<=L.length; ++ i) if(r[i].key < r[i-dk].key) { r[0]=r[i];//暫存在r[0] for(j=i-dk; j>0 &&(r[0].key<r[j].key); j=j-dk) r[j+dk]=r[j];//關鍵字較大的記錄在子表中後移 r[j+dk]=r[0];//在本趟結束時將r[i]插入到正確位置 } } void ShellSort(SqList &L,int dlta[ ],int t){ //按增量序列dlta[0…t-1]對順序表L做Shell排序 for(k=0;k<t;++k) ShellInsert(L,dlta[k]); //增量爲dlta[k]的一趟插入排序 } // ShellSort
時間複雜度是n和d的函數:O(n1.25)~O(1.6n1.25)
空間複雜度爲 O(1)
希爾排序是一種不穩定的排序方法
交換排序的基本思想是:兩兩比較待排序記錄的關鍵字,一旦發現兩個記錄不知足次序要求時則進行交換,知道整個序列所有知足要求爲止。
每趟不斷將記錄兩兩比較,並按「前小後大」 規則交換。
21,25,49, 25*,16, 08
21,25,25*,16, 08 , 49
21,25, 16, 08 ,25*,49
21,16, 08 ,25, 25*,49
16,08 ,21, 25, 25*,49
08,16, 21, 25, 25*,49
void bubble_sort(SqList &L) { int m,i,j,flag=1; RedType x; //flag用來標記某一列排序是否發生交換 m=n-1; while((m>0)&&(flag==1)) { flag=0; //置0,若是本趟排序沒有發生變換,咋補執行下一趟排序 for(j=1;j<=m;j++) if(L.r[j].key>L.r[j+1].key) { flag=1; //置1,表示本趟發生了交換 x=L.r[j]; L.r[j]=L.r[j+1]; L.r[j+1]=x; //交換 }//endif m--; }//endwhile }
時間複雜度爲 O(n2)
空間複雜度爲 O(1)
冒泡排序是一種穩定的排序方法
快速排序的基本思想是:從待排序記錄序列中選取一個記錄(一般選取第一個記錄)做爲「樞軸」(基準,支點),經過一趟排序(一次劃分)將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字比樞軸小,另外一部分記錄的關鍵字比樞軸大。而後則可分別對這兩部分記錄繼續進行劃分,以達到整個序列有序。
初始關鍵字 49 49* 65 97 17 27 50
一次交換 27 49* 65 97 17 49 50
二次交換 27 49* 49 97 17 65 50
三次交換 27 49* 17 97 49 65 50
四次交換 27 49* 17 49 97 65 50
int Partition(SqList &L, int low, int high) { KeyType pivotkey; pivotkey = L.r[low].key; while (low<high) { while ((low<high)&& (L.r[high].key>=pivotkey)) --high; L.r[low] ←→ L.r[high]; while ((low<high)&& (L.r[low].key<=pivotkey)) ++low; L.r[low] ←→ L.r[high]; } return low; // 返回樞軸位置 } // Partition
時間複雜度 O(nlog2n)
空間複雜度 O(log2n)
快速排序是一種不穩定排序。
從每趟待排序的記錄中選擇關鍵字最小的記錄,按順序放在已排序的記錄序列中,直到所有排完爲止。
(1)第一次從n個關鍵字中選擇一個最小值,肯定第一個;
(2)第二次再從剩餘元素中選擇一個最小值,肯定第二個;
(3)共需n-1次選擇。
設須要排序的表是A[n+1]:
(1)第一趟排序是在無序區A[1]到A[n]中選出最小的記錄,將它與A[1]交換,肯定最小值;
(2)第二趟排序是在A[2]到A[n]中選關鍵字最小的記錄,將它與A[2]交換,肯定次小值;
(3)第i趟排序是在A[i]到A[n]中選關鍵字最小的記錄,將它與A[i]交換;
(4)共n-1趟排序。
void SelectSort(SqList &L) {int i,j,low; for(i=1;i<L.length;i++) {low=i; for(j=i+1;j<=L.length;j++) if(L.r[j].key<L.r[low].key) low=j; if(i!=low) {L.r[0]=L.r[i]; L.r[i]=L.r[low]; L.r[low]=L.r[0]; } } }
簡單選擇排序方法是穩定的
時間複雜度O(n2)
空間複雜度O(1)。
樹形選擇排序,又稱錦標賽排序:按錦標賽的思想進行排序,目的是減小選擇排序中的重複比較次數。
輸出 6
輸出 8
樹形選擇排序方法是穩定的。
時間複雜度O(nlog2n)
空間複雜度O(n)
n個元素的序列A[1].key,A[2].key,…,A[n].key,當且僅當知足下述關係時,稱之爲堆。
小根堆:A[i].key≤A[2*i].key 且 A[i].key≤A[2*i+1].
大根堆:key A[i].key≥A[2*i].key 且 A[i].key≥A[2*i+1].key
void HeapAdjust(HeapType &H, int s, int m) {int j; RedType rc; rc = H.r[s]; for (j=2*s; j<=m; j*=2) {if (j<m && H.r[j].key<H.r[j+1].key) ++j; if (rc.key >= H.r[j].key) break; H.r[s] = H.r[j]; s = j; } H.r[s] = rc; // 插入 } // HeapAdjust
void HeapSort(HeapType &H) { int i; RcdType temp; for (i=H.length/2; i>0; --i) HeapAdjust ( H, i, H.length ); for (i=H.length; i>1; --i) { temp=H.r[i];H.r[i]=H.r[1]; H.r[1]=temp; HeapAdjust(H, 1, i-1); } } // HeapSort
堆排序是不穩定的排序。
時間複雜度爲O(nlog2n)。
最壞狀況下時間複雜度爲O(nlog2n)的算法。
空間複雜度爲O(1)。
又叫合併,兩個或兩個以上的有序序列合併成一個有序序列。
初始序列爲25, 57, 48, 37, 12, 82, 75, 29, 16, 請用二路歸併排序法排序。
for (j=m+1, k=i; i<=m && j<=n; ++k) { if LQ(SR[i].key,SR[j].key) TR[k] = SR[i++]; else TR[k] = SR[j++]; } if (i<=m) while (k<=n && i<=m) TR[k++]=SR[i++]; if (j<=n) while (k<=n &&j <=n) TR[k++]=SR[j++]; void MergeSort(RcdType A[],int n) {int l=1; Rcdtype B[]; while (l<n) {mpass(A,B,n,l) l=2*l; mpass(B,A,n,l); l=2*l; } }
歸併排序是穩定的排序方法。
時間複雜度爲O(nlog2n)
空間複雜度是O(n)
時間效率:O(d( n+rd))
空間效率:O(n+rd)
穩 定 性:穩定