算法思路:
每次從無序表中取出第一個元素,將其插入到有序表中的適當位置,使有序表的長度不斷加長,完成排序過程。
n個待排序的元素由一個有序表和一個無序表組成,開始時有序表中只包含一個元素。
流程演示:
藍色表示由有序表,黑色表示無序表!
分析
元素基本有序時,直接插入排序的時間復雜度接近於O(n)
元素數目n較少時,直接插入排序的效率較高
這是我排序的基礎,我的所有的排序算法都會依賴於這個簡單的順序表!
typedef int KeyType; // 定義關鍵字類型為整型
typedef int InfoType;
typedef struct {
KeyType key; // 關鍵字項
InfoType otherinfo; // 其他數據項
}RedType; // 記錄類型
typedef struct {
RedType r[MAXSIZE+1]; // r[0]閒置或用作哨兵
int length; // 順序表長度
}SqList;
void initSqList(SqList & S)
{
int t,count=0;
while(scanf("%d",&t)!=0)
{
count++;
S.r[count].key=t;
}
S.length=count;
}
void traverseSqList(SqList S)
{
for(int i=1;i<=S.length;i++)
printf("%d",S.r[i].key);
}
我們在這裡采用了優化,我們進行的是元素的移動和覆蓋,而不僅僅是簡單的交換。
void sortByDirectlyInsert(SqList &L)
{
for(int i = 2; i <= L.length; i++) //第一個元素默認有序,所以直接從2開始
if (L.r[i].key < L.r[i-1].key) { //這裡進行了優化,如果i >i-1,說明從1~i這一段都是有序的,我們不需要進行後續操作
L.r[0] = L.r[i];
L.r[i] = L.r[i-1];
int j;
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];
}//if
}
思路舉例:
[ ]5 9 6 3 8 //待排序元素
[ ]5 9 //到這裡是有序的
[ ]5 9 6 //到這裡發現6小於9
[6 ]5 9 空 //將6移到監視哨,把它的位置空出來
[6 ]5 空 9 //讓9來到原來6的位置,把9的位置空出來,看看6能不能填在那裡
[6 ]5 6 9 //6可以填在那裡,讓空的位置等於監視哨
[]5 6 9 3
[3 ]5 6 9 空
[3 ]5 6 空 9
[3 ]5 空 6 9
[3 ]空 5 6 9
[3 ]3 5 6 9
[]3 5 6 9 8
[8 ]3 5 6 9 空
[8 ]3 5 6 空 9
[8 ]3 5 6 8 9
[]3 5 6 8 9
我們這樣想,既然左半部分是是有序的,我們在有序的數組中找到插入位置,最好的方法非二分查找莫屬。
void sortByBinaryDirectlyInsert(SqList &L)
{
for(int i=2;i <= L.length; i++)
{ L.r[0] = L.r[i]; /* 保存待插入元素 */
int low = 1,high = i-1; /* 設置初始區間 */
while(low <= high) /* 確定插入位置 */
{ int mid = (low+high)/2;
if (L.r[0].key > L.r[mid].key)
low = mid+1; /* 插入位置在高半區中 */
else
high = mid-1; /* 插入位置在低半區中 */
}/* while */
for(int j = i - 1; j >= high +1; j--) /* high+1為插入位置 */
L.r[j+1] = L.r[j]; /* 後移元素,留出插入空位 */
L.r[high+1] = L.r[0]; /* 將元素插入 */
}/* for */
}
先將整個待排序元素序列分割成若干個小序列,在小序列內插入排序;
逐漸擴大小序列的長度(序列個數減少),使得整個序列基本有序;
最後再對全體元素進行一次直接插入排序。
void ShellInsert(SqList &L,int dk) {//對順序表L作一趟希爾排序
for(int i =dk+1; i <= L.length; i++)
if (L.r[i].key < L.r[i-dk].key) {
L.r[0] = L.r[i];
int j;
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];
}//if
} //ShellInsert
void ShellSort(SqList &L,int dlta[],int t) {
//按增量序列dlta[0..t-1]進行希爾排序
for(int k = 0; k < t; k++)
ShellInsert(L,dlta[k]); //一趟增量為dlta[k]的希爾排序
} //ShellSort
1.希爾排序的實質是插入排序!希爾排序的分析是一個復雜的問題,增量序列的設置是關鍵,尚沒有正式的依據說明何種設置最為合理!
2.空間復雜度為O(1),是一種不穩定的排序算法!