基本思想
每趟將一個待排序的對象,按其關鍵碼大小,插入到前面已經排序好的一組對象的適當位置
上,直到對象全部插入爲止。
即邊插入邊排序,保證子序列中隨時都是排好序的
插入排序算法的分類
直接插入排序
折半插入排序
希爾排序
直接插入排序
排序過程:整個排序過程爲n-1趟插入,即先將序列中第1個記錄看成是一個有
序子序列,然後從第2個記錄開始,逐個進行插入,直至整個序列有序。
void InsertSort(SqList &L)
{
int i,j;
for(i=2;i<L.length;++i)
if(L.r[i].key<L.r[i-1].key) //"<",需將r[i]插入有序子表
{
L.r[0]=L.r[i]; //將待插入的記錄暫時存在監視崗哨中
L.r[i]=L.r[i-1]; //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]; //將r[0]即原r[i],插入到正確位置
}
}
算法分析
設對象個數爲n,則執行n-1趟
比較次數和移動次數與初始排序有關
最好情況下:
每趟只需要比較1次,不移動
總比較次數爲n-1
最壞情況下:第i趟比較i次,移動i+1次
比較次數:KCN=(n+2)(n-1)/2=n*n/2
移動次數:RMN=(n+4)(n-1)/2=n*n/2
算法分析
若出現各種可能排序的概率相同,則可取最好情況和最壞情況的平均情況
平均情況比較次數和移動次數爲n*n/4時間複雜度爲O(n*n)
空間複雜度爲O(1)
是一種穩定的排序方法
折半插入排序
折半插入排序建立在直接插入排序的基礎上,是它的拓展出來的東西.
我們在將一個新元素插入已經排好序的數組的過程中,尋找插入點時,將待插入
區域的上限設置爲a[low],下限設置爲a【high】,然後將待插入元素與區間中間
位置a[m]進行比較,其中m=(low+high)/2
如果比中間位置a[m]小,則選擇a[low]到a[m-1]爲新的插入區域(即high=m-1),
如果比中間位置a[m]大,則選擇a[m+1]到a[high]爲新的插入區域(即low=m+1)
(3)如此直至low<=high不成立,即將此位置之後所有元素後移一位,並將新元素插入a[high+1]
Void BInserSort(SqList &L)
{
for(i=2;i<L.Length;++i)//對順序表L做折半插入排序
{
L.r[0]=L.r[i];//將待插入的記錄暫存到監視哨中
low=1;high=i-1;//置查找區間初值
while(low<=high) //在r[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]; //將r[0]即原r【i】,插入到正確位置
}
}
算法分析
折半查找比順序查找快,所以折半插入排序就平均性能來說比直接插入排序要快
它所需要的關鍵碼比較次數與待排序對象序列的初始化排列無關,僅依賴於對象個數。在插入第i個對象時,需要經過log2i+1次關鍵碼比較,才能確定它應插入的位置
當n較大時,總關鍵碼比較次數比直接插入排序的最壞情況要好得多,但其最好的情況要差
在對象的初始排列已經按關鍵碼排好序或接近有序時,直接插入排序比折半
插入排序執行的關鍵碼比較次數要少
折半插入排序的對象移動次數與直接插入排序相同,依賴於對象的初始排列
減少了比較次數,但沒有減少移動次數
平均性能優於直接插入排序
時間複雜度爲O(n*n)
空間複雜度爲O(1)
是一種穩定的排序方法
只能用於順序結構,不能用於鏈式結構
適合初始記錄無序,n較大的情況
希爾排序
希爾排序是1959年由D.L.Shell提出來的,相對直接插入排序有較大的改進。希爾排序又叫縮小增量排序。
算法思想的出發點:
直接插入排序在基本有序時,效率較高
在待排序的記錄個數較少時,效率較高
基本思想:
先將整個待排記錄序列按某個增量d分割成若干組子序列,每組中記錄的下標
相差d,分別對每組進行直接插入排序,然後再用一個較小的增量對它進行分
組,在每組中再進行直接插入排序。這樣當經過幾次分組排序後,待整個序
列中的記錄“基本有序”時,再對全體記錄進行一次直接插入排序。
技巧:
子序列的構成不是簡單地“逐段分割”將相隔某個增量dk的記錄組成一組子序
列讓增量dk逐趟縮短(例如依次取5,3,1)
直到dk=1爲止。
優點:
小元素跳躍式前移
最後一趟增量爲1時,序列已基本有序
平均性能優於直接插入排序
void ShellInsert(SqList &L,int dk) { for(i=dk+1;i<=L.length;++i) if(L.r[i].Key<L.r[i-dk].key) { L.r[0]=L.r[i]; 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]; } } void ShellSort(SqList &L,int dt[],int t) { for(k=0;k<t;++k) { ShellInsert(L,dt[k]); } }