基本思想: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-路插入排序。排序