資料結構之直接插入排序、折半插入排序、希爾排序演算法
哪個成功的人不是一路坎坷過來的,只有這樣你才知道珍惜,知道成功的不易。有時候太容易得到的東西反而不知道珍惜。
直接插入排序:
我們的記錄本身就是基本有序的,我們只需要少量的插入操作,就可以完成整個記錄集的排序工作,此時直接插入很高效。還有就是記錄數比較少時,直接插入的優勢也比較明顯。
void InsertSort(int b[],int n) //直接插入排序 { int i,j,t; for(i=0; i<n; i++) { t=b[i+1]; j=i; while(j>=0&&t<b[j]) { b[j+1]=b[j]; j--; } b[j+1]=t; } }
折半插入排序
演算法的流程就是:比如此時順序為5,3,2,4,1。分別對應陣列的a[0]...a[4]。
那麼當我們進入第一次插入演算法時,low=0;high=0;所以mid=0;此處用a[mid]即a[0]與我們所要插入的數a[1]即3進行比較。有a[mid]>3所以此時。我們就要在mid的左邊即low到mid之間進行比較了,但是mid又如何更新呢,就是要把high減1;然後再求mid就可以了,這時的新的mid就在low與原來的mid之間了。然後我們再次進行比較,但是此時因為high已經小於1了,所以迴圈終止,故將原有的資料後移一位,再將要插入的元素插入low處即可。
void BinInsertSort(int b[],int n) { int i,j,t,mid,low,high; for(i=0; i<n; i++) { t=b[i+1]; low=0; high=i; while(low<=high) { mid=(low+high)/2; if(b[mid]>t) high=mid-1; //在小於中間值的那部分尋找 else low=mid+1; //在大於中間值的那部分尋找 } for(j=i; j>=low; j--) { b[j+1]=b[j]; //整體陣列後移 } b[low]=t; } }
希爾排序:
希爾排序是基於插入排序的以下兩點性質而提出改進方法的:
1、插入排序在對幾乎已經排好序的資料操作時,效率高,即可以達到線性排序的效率。/
2、但插入排序一般來說是低效的,因為插入排序每次只能將資料移動一位。
希爾排序不需要大量的輔助空間,和歸併排序一樣容易實現。希爾排序是基於插入排序的一種演算法, 在此演算法基礎之上增加了一個新的特性,提高了效率。希爾排序的時間複雜度與增量序列的選取有關,例如希爾增量時間複雜度為O(n²),希爾排序時間複雜度的下界是n*log2n。希爾排序沒有快速排序演算法快 O(n(logn)),因此中等大小規模表現良好,對規模非常大的資料排序不是最優選擇。比O( n
希爾排序的思想就是,每隔一定增量的兩個數進行比較排序,然後得到一個得到一個基本有序的序列。這其實就是希爾排序的精華所在,它將關鍵字較小的記錄,不是一步一步地往前挪動,而是跳躍式地往前移,從而使得每次完成一輪迴圈後,整個序列就朝著有序堅實地邁進一步。
void ShellSort(int b[],int n)
{
int i,j,t;
int increment=n;
do
{
increment=increment/3+1; // 增量序列
for(i=increment; i<=n; i++)
{
if (b[i]<b[i-increment]) //需將b[i]插入有序增量子表
{
t=b[i]; // 暫存在t
for(j=i-increment; j>=0 && t<b[j]; j-=increment)
b[j+increment]=b[j]; // 記錄後移,查詢插入位置
b[j+increment]=t; //插入
}
}
}
while(increment>1);
}
測試程式如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void InsertSort(int a[],int n) //直接插入排序
{
int i,j,t;
int b[n];
memcpy(b, a, n * sizeof(int));
for(i=0; i<n; i++)
{
t=b[i+1];
j=i;
while(j>=0&&t<b[j])
{
b[j+1]=b[j];
j--;
}
b[j+1]=t;
}
for(i=0; i<n; i++)
printf("%4d",b[i]);
}
void BinInsertSort(int a[],int n)
{
int i,j,t,mid,low,high;
int b[n];
memcpy(b,a,n*sizeof(int));
for(i=0; i<n; i++)
{
t=b[i+1];
low=0;
high=i;
while(low<=high)
{
mid=(low+high)/2;
if(b[mid]>t)
high=mid-1; //在小於中間值的那部分尋找
else
low=mid+1; //在大於中間值的那部分尋找
}
for(j=i; j>=low; j--)
{
b[j+1]=b[j]; //整體陣列後移
}
b[low]=t;
}
for(i=0; i<n; i++)
printf("%4d",b[i]);
}
void ShellSort(int a[],int n)
{
int i,j,t;
int b[n];
memcpy(b,a,n*sizeof(int));
int increment=n;
do
{
increment=increment/3+1; // 增量序列
for(i=increment; i<=n; i++)
{
if (b[i]<b[i-increment]) //需將b[i]插入有序增量子表
{
t=b[i]; // 暫存在t
for(j=i-increment; j>=0 && t<b[j]; j-=increment)
b[j+increment]=b[j]; // 記錄後移,查詢插入位置
b[j+increment]=t; //插入
}
}
}
while(increment>1);
for(i=0; i<n; i++)
printf("%4d",b[i]);
}
int main()
{
int i;
int p[5]= {5,3,2,4,1};
printf("原序:");
for(i=0; i<5; i++)
printf("%4d",p[i]);
printf("\n直接插入排序:");
InsertSort(p,5);
printf("\n折半插入排序:");
BinInsertSort(p,5);
printf("\n希爾排序:");
ShellSort(p,5);
return 0;
}
結果: