排序(1)--插入排序和交換排序
首先引入幾個概念:
內部排序:整個排序過程不需要訪問外存便能完成。
外部排序:參加排序的記錄數量很大,整個序列的排序過程不可能在記憶體中完成。
穩定性和不穩定性: 設 Ki、Kj (1≤i≤n, 1≤j≤n, i≠j ) 分別為記錄 Ri、Rj 的關鍵字,且 Ki = Kj ,在排序前的序列中 Ri 領先於 Rj (即 i < j )。若在排序後的序列中 Ri 仍領先於 Rj ,則稱所用的排序方法是穩定的;反之,則稱所用的排序方法是不穩定的。
一.插入排序:
1.直接插入排序:
(1)思想: 對第i個元素,把它插入到前i-1個元素(已經有序)裡面(2<=i<=n)
(2).實現:
void InsertSort(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];
L.r[i]=L.r[i-1];
for(j=i-2;L.r[0].key<L.r[j].key;j--)
{
L.r[j+1]=L.r[j];//記錄後移
}
L.r[j+1]=L.r[0];//插入到正確位置
}
}
}
(3).演算法效能分析:
時間複雜度:最好情況:全部有序,那麼移動次數為0;
最壞情況:全部逆序,移動次數為
取移動次數的平均數得演算法時間複雜度為:O(n2)
穩定性:鍵碼相同的兩個記錄,在整個排序過程中,不會通過比較而相互交換,所以是穩定的。
2.折半插入排序:
(1)思想:考慮到 L.r[1,..,i-1] 是按關鍵字有序的有序序列,則可以利用折半查詢實現“L.r[1,…,i-1]中查詢 L.r[i] 的插入位置”如此實現的插入排序為折半插入排序。
(2).實現:
void BinsertSort(SqList &L){ // 折半插入排序
int i,low,high,mid;
for(i=2; i<= L.length; ++i) {
L.r[0]=L.r[i]; //將L.r [i] 暫存到L.r[0]
low=1; high=i-1;
While(low<=high) { //比較,折半查詢插入位置
mid=(low+high)/2; // 折半
if (L.r[0].key< L.r[mid].key) high=mid-1; //插入點在低半區
else low=mid+1; } // 插入點在高半區
for( j=i-1; j>=low; --j ) L.r[j+1]=L.r[j]; // 記錄後移
L.r[low]=L.r[0]; } // 插入
} // BInsertSort
(3).演算法效能分析:
時間複雜度: 折半查詢比順序查詢快,所以折半插入排序就平均效能來說比直接插入排序要快。
折半插入排序減少了關鍵數的比較次數,但記錄的移動次數不變,其時間複雜度與直接插入排序相同。
穩定性:穩定。
3.希爾插入排序:
(1)思想:先將整個待排記錄序列分割成若干子序列,分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對全體記錄進行一次直接插入排序。
子序列的構成不是簡單地“逐段分割”,而是將相隔某個增量dk的記錄組成一個子序列,讓增量dk逐趟縮短(例如依次取5,3,1),直到dk=1為止
(2)實現:
void ShellInsert ( SqList &L, int dk )
{ //一趟希爾插入排序
//1.前後記錄位置的增量是dk;
//2.L.r[0]只是暫存單元,不是哨兵。當j<=0時,插入位置已找到
for ( i=dk+1; i<=L.length; ++i )
if ( L.r[i].key< L.r[i-dk].key) {//將R[i]插入有序增量子表
L.r[0] = L.r[i]; // 暫存在R[0]
for (j=i-dk; j>0 && (L.r[0].key< L.r[j].key);j -= dk)
L.r[j+dk] = L.r[j]; // 記錄後移,查詢插入位置
L.r[j+dk] = L.r[0]; // 插入
}
}//ShellInsert
void ShellSort (SqList &L, int dlta[ ], int t)
{
// 按增量序列dlta[0..t-1]對順序表L作希爾排序
for (k=0; k<t; ++k)
ShellInsert( L, dlta[k]); // 一趟增量為dlta[k]的插入排序
} // ShellSort
(3)效能分析:
開始時dk 的值較大,子序列中的物件較少,排序速度較快;隨著排序進展,dk 值逐漸變小,子序列中物件個數逐漸變多,由於前面工作的基礎,大多數對 象已基本有序,所以排序速度仍然很快。
時間複雜度:——所選增量比較合理
空間效率:O(1) —— 因為僅佔用1個緩衝單元
穩定性:希爾排序選取增量的時候都是一個一個子序列比較的,很容易導致後一個數排到前一個數前面去,所以不穩定!
二.交換排序:
1.氣泡排序:
(1)思想:每一輪都是兩兩相鄰比較,直到小的浮起或大的沉底
(2)實現:
void Bubblesort(ElemType R[],int n) {
int flag=1; //當flag為0則停止排序
for (int i=n; i>1; i--) { //i表示趟數,最多n-1趟
flag=0; //開始時元素未交換
for (int j=2; j<=i; j++)
if (R[j]<R[j-1]) { //發生逆序
temp=R[j]; R[j]=R[j-1]; R[j-1]=temp;
flag=1;
}
if(flag==0) return;
}
} // Bubblesort
(3)演算法分析:
時間複雜度:O(n2),可以取最好情況和做差情況取平均
穩定性:穩定
起泡排序的過程可見,起泡排序是一個增加有序序列長度的過程,也是一個縮小無序序列長度的過程,每經過一趟起泡,無序序列的長度只縮小1。
試設想:若能在經過一趟排序,使無序序列的長度縮小一半,則必能加快排序的速度。
2.快速排序:
(1)思想:通過一趟排序將待排序列以樞軸為標準劃分成兩部分,使其中一部分記錄的關鍵字均比另一部分小,另一部分大,再分別對這兩部分進行快速排序,以達到 整個序列有序(通常取第一個記錄的值為基準值或樞軸).
(2)實現:
void QSort ( Elem R[ ], int low, int high ){ //對序列R[low...high]進行快速排序
if (low < high-1) { //長度大於1
pivot = Partition( L,low,high); //將R[low..high]一分為二
QSort(L,low, pivot-1); //對低子表遞迴排序,pivo是樞軸
QSort(L, pivot+1, high); // 對高子表遞迴排序
}
} // QSort
void QuickSort(Elem R[], int n){ //對記錄序列進行快速排序
QSort(R, 1, n);
} // QuickSort
int Partition (Elem R[ ], int low, int high){
R[0] = R[low]; pivotkey = R[low].key;
while (low < high) { //從兩端交替向中間掃描
while (low < high && R[high].key >= pivotkey) - - high;
R[low] = R[high]; //將比樞軸記錄小的移到低端
while (low < high && R[low].key <= pivotkey) + + low;
R[high] = R[low]; //將比樞軸記錄大的移到高階
}
R[low] = R[0]; //樞軸記錄到位
return low; //返回樞軸位置
} // Partition
(3)演算法效能分析:
時間複雜度:
空間複雜度:快速排序是遞迴的,需要有一個棧存放每層遞迴呼叫時的指標和引數(新的low和high)。最大遞迴呼叫層次數與遞迴樹的深度一致,理想情況為 └ log2n ┘ + 1(向下取整) 。因此,要求儲存開銷為 O(log2n)
穩定性:不穩定。
相關文章
- 非交換排序-計數排序和桶排序排序
- 排序專題 -- (1)插入排序排序
- 插入排序排序排序
- 三種插入排序 直接插入排序,折半插入排序,希爾排序排序
- 排序演算法 - 快速插入排序和希爾排序排序演算法
- go 實現氣泡排序和插入排序Go排序
- 插入排序排序
- php插入排序,快速排序,歸併排序,堆排序PHP排序
- 【排序】插入類排序—(折半)插入排序、希爾排序排序
- 用JS實現氣泡排序和插入排序JS排序
- 選擇排序和插入排序(C++實現)排序C++
- 桶排序 選擇,插入排序排序
- rust-algorithms:1-插入排序RustGo排序
- 利用java實現插入排序、歸併排序、快排和堆排序Java排序
- 03 插入排序排序
- python插入排序Python排序
- 排序演算法__折半插入排序排序演算法
- 氣泡排序 插入排序 快排排序
- 排序演算法(氣泡排序,選擇排序,插入排序,希爾排序)排序演算法
- Java實現氣泡排序和插入排序演算法Java排序演算法
- php實現 氣泡排序,插入排序,選擇排序PHP排序
- 408 DataStructure_Algorithm - 8.3 交換排序ASTStructGo排序
- PHP 常見4種排序 氣泡排序、選擇排序、插入排序、快速排序PHP排序
- 圖解選擇排序與插入排序圖解排序
- PHP 排序演算法之插入排序PHP排序演算法
- 排序演算法之折半插入排序排序演算法
- 如何理解插入排序?排序
- 插入排序-by-Python排序Python
- 插入排序(Insertion Sort)排序
- 排序演算法__直接插入排序排序演算法
- 排序演算法:直接插入排序排序演算法
- 排序演算法入門之「插入排序」排序演算法
- 排序演算法(3)插入排序(Insertion Sort)排序演算法
- 排序演算法——直接插入排序排序演算法
- 排序演算法之「插入排序(Insertion Sort)」排序演算法
- 排序之交換排序排序
- 插入排序以及優化排序優化
- 連結串列-插入排序排序
- JavaScript實現:插入排序!!!JavaScript排序