排序按記錄是否所有在內存操做份內排序和外排序;按記錄排序前的前後位置關係與排序後的前後位置不變分穩定性排序和不穩定性排序;按平均時間複雜度可分O(n2),O(nlogn);按算法行爲可分爲插入排序(直接插入排序,希爾排序)、選擇排序(簡單選擇排序、堆排序)、交換排序(冒泡派訊,快速排序),歸併排序(歸併排序)。算法
冒泡排序:從後面開始兩兩比較,記錄上浮。改進,對已經排序的部分作標記,再也不進行交換。平均時間複雜度O(n2);最好是O(n),最壞O(n2);空間複雜度是O(1);spa
For(int I = 1; I >=L->length; I ++){指針
//下標從1開始htm
For(int j = L->length -1; j>=i;j--){排序
If(L[j]> L[j+1]){遞歸
Swap(L, j,j+1);內存
}rem
}get
}ast
改進:
Status flag = true;
For(int I = 1; I >=L->length&& flag; I ++){
//下標從1開始
Flag = false;
For(int j = L->length -1; j>=i;j--){
If(L[j]> L[j+1]){
Swap(L, j,j+1);
Flag= true;
}
}
}
直接插入排序:從記錄開頭開始,將記錄分爲有序與無序兩部分,不斷地將無序部分的記錄與有序部分比較,插入到有序部分,插入位置後的有序部分相對地日後移動一位。平均時間複雜度O(n2),最好是O(n);最壞是O(n2);空間複雜度爲O(1);
For(int I = 2; I >=L->length; I ++){
//下標從1開始
If(L[i]<L[i-1]){
Int key = L[i];
For(int j = i-1; L[j]>key;j--){
L[j+1] = L[j];
L[j+1]=key;
}
}
}
簡單選擇排序:基本思想是找出餘下記錄中最小的記錄,將其與當前位置記錄交換。經過n-i次關鍵字比較,從n-i+1各記錄中選出關鍵字最小的記錄,並和第i各記錄交換之。平均時間複雜度O(n2),最好是O(n2);最壞是O(n2);空間複雜度爲O(1);
For(int I = 1; I <=L->length; I ++){
//下標從1開始
min = I;
For(int j = i+1; j> L->Length;j++){
If(L[j]> L[min]){
min = j;
}
}
If(I!=min)Swap(L,I, min );
}
希爾排序:基本思想是先作到基本有序再作到總體有序。方法:選擇一個增量(軸),不斷比較軸尾與軸頭,交換軸長兩端;而後軸長不斷減少,進行上一步。平均時間複雜度爲O(nlog(n))~O(n2);最好O(n1.3),最壞O(n2);不穩定排序。
先取一個小於n的整數d1做爲第一個增量,把文件的所有記錄分組。全部距離爲d1的倍數的記錄放在同一個組中。先在各組內進行直接插入排序;而後,取第二個增量d2<d1重複上述的分組和排序,直至所取的增量 =1( < …<d2<d1),即全部記錄放在同一組中進行直接插入排序爲止。
Int increment = L->Length;
Do{
Increment = increment/3 + 1;
For(int I = increment +1; i <=L->Length; I ++){
//下標從1開始
Int key = L[i];
If(key < L[i-increment]){
For(int j = I – increment; L[j] < key&&j>0; j-=increment){
L[j+ increment] = L[j];
L[j+ increment] = key;
}
}
}while(increment>1)
堆排序:將記錄構造爲大頂堆,將最後一個葉節點與根節點(最大)交換,餘下的繼續構造爲大頂堆。平均時間複雜度O(nlogn),最好O(nlogn),最壞也是O(nlogn);空間複雜度爲O(1);爲不穩定排序。
構造大頂堆:(要點:下標從小到大遍歷父節點保證每一個父節點大於左右孩子節點)
Void HeadAdjust(SaList *L, int s, int m){
Int length = m-s+1;
Int last_f =length/2;
Last_f = Last_f <1?1: Last_f;//下標從1開始
For(int I = last_f; I >=1; i--){
Int tmp = 2*I;
If(tmp <length && L[tmp] <L[tmp+1])
Tmp += 1;
If(L[i]<L[tmp])swap(L, I, tmp);
}
}
以上算法缺陷在每次調整都要遍歷全部父節點,而如下的只須要遍歷變化的父節點。
Void HeadAdjust(SaList *L, int s, int m){
Int temp, j;
Temp = L[s];
For(j = 2*s; j<=m; j*=2){
If(j<m && L[j] <L[j+1])
++j;
If(temp >= L[j])
Break;
L[s] = L[j];
s = j;//直接指向修改過的樹的根節點
}
L[s]= temp;
}
快速排序:將記錄分爲比樞軸(pivot)小和比樞軸大兩部分。如此不斷地遞歸分割。平均時間複雜度O(nlogn),最好爲O(nlogn)最差爲O(n^2);空間複雜度爲O(logn)~O(n);爲不穩定算法。
void Qsort(int a[],int low,int high)
{
//算法要點:從尾部開始,首尾交替向中間移動(首部停在比pivot大的元素(比pivot小則與pivot交換,), 尾部停在比pivot小的元素(比pivot大則不改變向前移動), 兩元素交換),直到首尾指針下標重疊,則該位置爲pivot位置,設置該位置值爲樞軸。
if(low>=high) return;
int first=low;
int last=high;
int key=a[first];/*用字表的第一個記錄做爲樞軸*/
while(first<last)
{
while(first<last&&a[last]>=key) --last;
a[first]=a[last];/*將比第一個小的移到低端*/
while(first<last&&a[first]<=key) ++first;
a[last]=a[first];/*將比第一個大的移到高端*/
}
a[first]=key;/*樞軸記錄到位*/
Qsort(a,low,first-1);
Qsort(a,first+1,high);
}
歸併算法:將n個記錄的待排序序列,看作n個有序的子序列,而後兩兩歸併,獲得不大於n/2個長度爲2或1的有序子序列,在兩兩歸併,……,如此重複,直到獲得一個長度爲n的有序序列。平均時間複雜度O(nlogn),最好O(nlogn),最壞也是O(nlogn);空間複雜度爲O(n);
基本有序的記錄:用簡單的算法便可:冒泡,簡單選擇、直接插入。