直接插入排序中加入了附加记录,又称监视哨或者哨兵。
哨兵的主要作用:
① 进人查找(插入位置)循环之前,它保存了R[i]的副本,使不致于因记录后移而丢失R[i]的内容;
② 它的主要作用是:在查找循环中监视下标变量j是否越界。一旦越界(即j=0),因为R[0].可以和自己比较,循环判定条件不成立使得查找循环结束,从而避免了在该循环内的每一次均要检测j是否越界(即省略了循环判定条件j>=1)。
下面的c函数,是基础的直接插入排序,但是更容易帮助理解哨兵的意思
void
//待排序元素用一个数组a表示,数组有n个元素
{
}
上面的temp就相当于哨兵的意思
下面是改进版的算法:
void lnsertSort(SeqList R)
{ //对顺序表R中的记录R[1..n]按递增序进行插入排序
int i,j;
for(i=2;i<=n;i++) //依次插入R[2],…,R[n]
if(R[i].key<R[i-1].key){ //若R[i].key大于等于有序区中所有的keys,则R[i]
//应在原有位置上
R[0]=R[i];j=i-1; //R[0]是哨兵,且是R[i]的副本
do{ //从右向左在有序区R[1..i-1]中查找R[i]的插入位置
R[j+1]=R[j]; //将关键字大于R[i].key的记录后移
j-- ;
}while(R[0].key<R[j].key); //当R[i].key≥R[j].key时终止
R[j+1]=R[0]; //R[i]插入到正确的位置上
}//endif
}
算法用c语言实现了,现在来分析一下时间复杂度和空间复杂度
从空间上:
只需要一个哨兵来辅助,因此空间复杂度为O(1)
从时间上:
最好的情况:所有的序列本来就是是需要的序列(顺序或者逆序),但还是需要遍历一遍所有元素,那个器时间复杂度为O(n)
最坏的情况:所有的序列和需要的序列恰恰相反,需要(1,2,3,4,5),原序列是(5,4,3,2,1),那就需要在遍历每一个元素的时候,要进行一波与前面元素的交换,此时的时间复杂度为2+3+4+...+n 其时间复杂度为O(n2)
一般情况:排序记录是随机的,
稳定性:稳定的