基本思想:
先将整个待排记录序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
优点:
让关键字值小的元素能很快前移,且序列若基本有序时,再用直接插入排序处理,时间效率会高很多。
技巧:
子序列的构成不是简单地“逐段分割”,而是将相隔某个增量dk的记录组成一个子序列,让增量dk逐趟缩短(例如依次取5,3,1),直到dk=1为止。
空间效率:
void ShellSort(SqList &L,int dlta[ ],int t){ //按增量序列dlta[0…t-1]对顺序表L作Shell排序。dk值依次装在dlta[t]中 for(k=0;k<t;++k) ShellInsert(L,dlta[k]); //增量为dlta[k]的一趟插入排序。 } void ShellInsert(SqList &L,int dk) { //对顺序表L进行一趟增量为dk的Shell排序,dk为步长因子 for(i=dk+1;i<=L.length; ++ i) if(r[i].key < r[i-dk].key) {//开始将r[i] 插入有序增量子表 r[0]=r[i];//暂存在r[0] ,此处r[0]仍是哨兵 for(j=i-dk; j>0&&(r[0].key<r[j].key); j-=dk) r[j+dk]=r[j]; //如果没有此句,就只能实现相临的两个数之间的比较,而不能两两都比较到,所以有可能达不到排序的目的。 r[j+dk]=r[0];//在本趟结束时将r[i]插入到正确位置 } }
O(1)——因为仅占用1个缓冲单元