基本思想:java
將一個記錄插入到已排序好的有序表中,從而獲得一個新,記錄數增1的有序表。即:先將序列的第1個記錄當作是一個有序的子序列,而後從第2個記錄逐個進行插插入到已入,直至整個序列有序爲止。ios
要點:設立哨兵,做爲臨時存儲和判斷數組邊界之用。算法
直接插入排序示例:數組
若是遇見一個和插入元素相等的,那麼插入元素把想插入的元素放在相等元素的後面。因此,相等元素的先後順序沒有改變,從原無序序列出去的順序就是排好序後的順序,因此插入排序是穩定的。測試
哨兵的做用
算法中引進的附加記錄R[0]稱監視哨或哨兵(Sentinel)。
哨兵有兩個做用:
① 進人查找(插入位置)循環以前,它保存了R[i]的副本,使不致於因記錄後移而丟失R[i]的內容;
② 它的主要做用是:在查找循環中"監視"下標變量j是否越界。一旦越界(即j=0),由於R[0].能夠和本身比較,循環斷定條件不成立使得查找循環結束,從而避免了在該循環內的每一次均要檢測j是否越界(即省略了循環斷定條件"j>=1")。
注意:
① 實際上,一切爲簡化邊界條件而引入的附加結點(元素)都可稱爲哨兵。
【例】單鏈表中的頭結點其實是一個哨兵
② 引入哨兵後使得測試查找循環條件的時間大約減小了一半,因此對於記錄數較大的文件節約的時間就至關可觀。對於相似於排序這樣使用頻率很是高的算法,要儘量地減小其運行時間。因此不能把上述算法中的哨兵視爲雕蟲小技,而應該深入理解並掌握這種技巧。
算法的實現:
spa
#include<iostream>
using namespace std;
int
main()
{
int
a[]={
98
,
76
,
109
,
34
,
67
,
190
,
80
,
12
,
14
,
89
,
1
};
int
k=sizeof(a)/sizeof(a[
0
]);
int
j;
for
(
int
i=
1
;i<k;i++)
//循環從第2個元素開始
{
if
(a[i]<a[i-
1
])
{
int
move
=a[i];
for
(j=i-
1
;j>=
0
&& a[j]>move;j--)//a[j]若小於要挪動的數,則是循環終止的條件
{
a[j+
1
]=a[j];//將a[i]前元素向後挪動一個
}
a[j+
1
]=move;
//此處就是a[j+1]=move;
}
}
for
(
int
f=
0
;f<k;f++)
{
cout<<a[f]<<
" "
;
}
return
0
;
}
效率:code
時間複雜度:O(n^2).blog
其餘的插入排序有二分插入排序,2-路插入排序。排序