Shell排序:
将整个序列划分成若干子序列,对每个子序列进行直接插入排序。
步骤:
1.产生取值间隔gap,保存到distance数组中。(gap=[gap]/2)
distance[0]=n/2; //distance 数组初始化
i=1;
While(true)
{
d=distance[i-1]/2;
distance[i]=d;
if(distance[i]==1)break;
i++;
}
2.每一个gap,确定一个子序列划分方法。假设有如下数组:
gap应取5、2、1三个数。
(1)gap=5,应形成5个子序列,其中每个子序列包含两个元素:
A[0]A[5] A[1]A[6] A[2]A[7] A[3]A[8] A[4]A[9]
(2)gap=2,应形成2个子序列,每个子序列包含5个元素:
A[0]A[2]A[4]A[6]A[8] A[1]A[3]A[5]A[7]A[9]
(3)gap=1,一个子序列:
A[0]A[1]…A[9]
3.每个gap,需要进行gap个直接插入排序。即 for(i=0;i<gap;i++)
4.设计单个序列的直接插入排序。
主要程序实现步骤:
for(i=0;i<gap;i++) //gap次直接插入排序
{
//直接插入排序
for(j=1;j<n/gap;j++) //假设第一个元素有序,扫描其后的待排序元素。第i个子序列,要扫描n/gap-1次
//这个子序列中的元素:(A[i]A[i+gap]A[i+2gap]…A[i+(n/gap-1)*gap])
//即A[i],A[i+j*gap]
{
if(A[i+j*gap]<A[i+(j-1)*gap])//逆序
{
temp=A[i+j*gap];
//寻找插入位置
for(k=0,k<j*gap;k+=gap) //若待排序元素为A[i+j*gap],前面排好序的元素有j个.
{
if(A[i+j*gap]>A[i+k])
continue;
else //插入位置为A[i+k],待排序元素为A[i+j*gap]
{
for(m=0;m<j-k/gap;m++) //并移动{[i+j*gap-(i+k)]/gap}个元素
{
A[i+(j-m)*gap]=A[i+(j-m-1)*gap]
}
A[i+k]=temp;
}
}
}/*if*/
else continue; //未逆序,继续扫描下一个元素。
}
}
总结:共需5个for循环。分别是从distance数组中提取gap循环,gap子序列循环,剩下的是直接插入排序中的三个循环。即:扫描待排序元素循环,寻找插入位置循环,移动元素循环。
设计循环主要是设定循环的起点、终点和步长。