七大排序速查版
通用結(jié)構(gòu)體:
View Code typedef struct{
int r[MAXSIZE+1]; //下標(biāo)從1開始用,0為哨兵或其他用
int length;
}SqList;
一.選擇排序
1.1簡單選擇排序:
(1)思路:
通過n-i次關(guān)鍵字比較,從n-i+1個記錄中選出關(guān)鍵字最小的記錄,并和第i個記錄交換.
(2)代碼:
View Code void SelectSort(Sqlist *L){
int i, j, min;
for(i=1; i<L->length; i++)
{
for(j=i+1; j<L->length; j++)
{
min = i;
if(L->r[j] < L->r[min])
min = j;
}
if(i != min)
swap(L,i,min);
}
}
?
(3)時間復(fù)雜度:
由兩個for循環(huán)知,時間復(fù)雜度為(n^2).
?
1.2堆排
(1)相關(guān)定義:
堆是一種完全二叉樹,當(dāng)結(jié)點值>=其左右孩子結(jié)點時,為大頂堆;反之,小頂堆.
(2)產(chǎn)生背景:
由簡單排序改良而來.簡單選擇排序第1次從n個數(shù)中取最小需要n-1次比較,但第2次從n-1個中選又要n-1-1次比較,沒利用好之前的比較.堆排則利用了,體現(xiàn)在建完大頂堆后,結(jié)點值大于孩子結(jié)點,所以重新調(diào)整時,比較的次數(shù)就大大縮減.
(3)使用步驟:
1.先建大頂堆 2.輸出最大值并重調(diào)
(4)代碼:
View Code //從上往下調(diào)整,使得L->r[s..m]滿足大頂堆的定義void HeapAdjust(SqList *L, int s, int m)
{
int temp, j;
temp = L->r[s];
for(j=2*s; j<m; j*=2)
{
if(j<m && L->r[j]<L->r[j+1])
j++;
if(temp > L->r[s])
break;
L->r[s] = L->r[j];
s = j;
}
L->r[s] = temp;
}
void HeapSort(SqList *L)
{
int i;
for(i=L->length/2; i>0; i--)
{
HeapAdjust(L,i,L->length); //從下往上,從右往左調(diào),這樣for循環(huán)結(jié)束后,堆已變成大頂堆;
}
for(i=L->length; i>0; i--)
{
swap(L,1,i); //輸出堆頂元素,然后將最后一個與其交換
HeapAdjust(L,1,i-1); //從新調(diào)整堆;
}
}
?
(5)時間復(fù)雜度
由完全二叉樹性質(zhì)知,深度為log2n +1,即調(diào)用一次調(diào)整要logn時間,而堆排要調(diào)用n-1次,所以時間復(fù)雜度為(nlogn).
?
二.交換排序
2.1冒泡排序
(1)思路:
從下往上冒泡,每次都將最小的冒到最上,即第i次則將第i小的數(shù)冒泡到第i個位置上
(2)代碼:
View Code?
(3)事件復(fù)雜度:
由兩個for循環(huán)可知,時間復(fù)雜度為(n^2).
?
2.2快排
(1)思路:
基于分治策略,將一個大的序列按某個值比較,按值大于或小于篩選分成兩個小的序列,然后按之前的原則分別再繼續(xù)細(xì)分,直到長度為1則排序完成.
(2)代碼:
View Code int Partion(SqList *L, int low, int high){
int pivot;
pivot = L->r[low]; //為達(dá)到更高效率,比較好的是取頭,尾,中三個數(shù)中第二大的數(shù)為'樞軸值'
if(low < high)
{
while(low<high && L->r[high]>=pivot)
high--;
L->r[row] = L->r[high];
while(low<high && L->r[low]<=pivot)
low++;
L->r[high] = L->r[low];
}
L->r[low] = pivot;
return low; //返回'樞軸值'
}
void QuikSort(SqList *L, int low, int high)
{
int pivot;
if(low < high)
{
pivot = partion(L,low,high); //將原序列一份為二
QuikSort(L,low,pivot); //遞歸調(diào)用左邊區(qū)間
QuikeSort(L,pivot+1,high); //遞歸調(diào)用右區(qū)間
}
}
?
(3)時間復(fù)雜度
最優(yōu)情況為:樞軸值為序列中第n/2大的樹,則有:
T(n) = 2T(n/2) + f(n)??? //f(n)為將一個序列劃分為更小的序列所需的時間,這里f(n)=n
用主方法可知,時間復(fù)雜度為(nlogn).
最差情況為:序列為從小到大排好的,而且樞軸值為第一個,則退化為冒泡排序,時間復(fù)雜度為(n^2).
?
三.插入排序
3.1直接插入排序
(1)思路:
將一個記錄插入到已經(jīng)排好序的有序序列中,從而得到一個新的記錄數(shù)加1的有序序列.
(2)代碼:
View Code void InsertSort(SqList *L){
int i,j;
for(i=2; i<L->length; i++)
{
if(L->r[i] < L->r[i-1]) //將L->r[i]插入到有序序列中
{
L->r[0] = L->r[i]; //哨兵,暫存值
for(j=i-1; L->r[j]>L->r[0]; j--)
{
L->r[j+1] = L->r[j]; //比L->r[i]大的,向后挪,騰出位子來
}
L->r[j+1] = L->r[0]; //j+1是由于for循環(huán)最后多減了1
}
}
}
?
(3)時間復(fù)雜度:(n^2).
?
3.2希爾排序
(1)思路:
直接插入排序的改良版.先用比較大的間隔的數(shù)去使用插入排序,然后逐步縮減間隔大小,直到為1.即讓序列每次排序后越來越接近有序序列.
(2)代碼:
View Code void ShellSort(SqList *L){
int i, j;
int increment = L->length;
while(increment>1)
{
increment = increment/3 +1; //相對來說比較好的一個間隔數(shù)
for(i=increment+1; i<=L->length; i++)
{
if(L->r[i] < L->r[i-increment])
{
L->r[0] = L->r[i];
for(j=i-increment; L->r[j]>L->r[0]; j=j-increment)
{
L->r[j+increment] = L->r[j];
}
L->r[j+increment] = L->r[0];
}
}
}
}
?
(3)時間復(fù)雜度:
大量的研究表明,當(dāng)增量序列為dlta[k]=2t-k+1-1(0≤k≤t≤?log2(n+1)?)時,可以獲得不錯的效率,其時間復(fù)雜度為O(n3/2),要好于直接排序的O(n2)。
?
四.歸并排序
歸并排序
(1)思路:
典型的分治策略,分而治之,分到1個1個,再兩兩合并成有序序列.
(2)步驟:
需要一個臨時數(shù)組來裝分出來的兩個序列.
(2)代碼:
View Code void MergeSort(SqList *L){
MSort(L->r, L->r, 1, L->length);
}
void MSort(int SR[],int TR1[], int s, int t) //將SR[s..t]歸并排序為TR1[s..t]
{
int m;
int TR2[MAXSIZE+1]; //臨時數(shù)組,用來在相鄰遞歸函數(shù)之間傳遞數(shù)據(jù)
if(s==t) //3遞歸結(jié)束條件,即每個數(shù)組只有一個元素
TR1[s] = SR[s];
else
{
m = (s+t)/2; //1平分SR,然后從兩個序列中繼續(xù)遞歸調(diào)用
MSort(SR,TR2,s,m);
MSort(SR,TR2,m+1,t);
Merge(TR2,TR1,s,m,t); //2將TR2[s..m]和TR2[m+1..t]合并到TR1[s..t]中
}
}
void Merge(int SR[], int TR[], int i, int m, int n)
{
int j, k, l;
for(k=i,j=m+1; (i<=m)&&(j<=n); k++)
{
if(SR[i]<SR[j])
TR[K] = SR[i++];
else
TR[K] = SR[j++];
}
//跳出for循環(huán)則說明有一組已經(jīng)全部插入TR[]中,所以將剩下的全部復(fù)制到TR[]后面即可
if(i<=m) //i<=m,則說明j>n即j已經(jīng)插完
for(l=1; l<=m; l++)
TR[k+1] = SR[i+1];
if(j<=n)
for(l=1; l<=n; l++)
TR[k+1] = SR[j+1];
}
?
(3)時間復(fù)雜度:
T(n) = 2T(n/2) + n-1??? //n-1為將n個數(shù)分成一個一個以及兩兩合并的時間,由于n個要比較n-1次
由主方法可知,時間復(fù)雜度為(nlogn).
轉(zhuǎn)載于:https://www.cnblogs.com/Quains/archive/2012/04/03/2430607.html
總結(jié)
- 上一篇: 矩阵快速幂 学习笔记
- 下一篇: HDU 1874 畅通工程续