希尔排序
希尔排序本身也是一种插入排序方法基本思想:提升插入排序的效率,插入排序效率相对低下的原因是在插入过程中,当找到了待插入元素A[r+1]的位置k后,A[k].....A[r]都需要每次一步后移,为待插入元素腾位置,但是希尔排序通过设置步长,一次跳跃多步,避免一次一步这样慢慢的挪移,在后续的排序中,能够减少比较和移动的次数,以提高程序的效率
打个比方,数据A[1......r]是升序的,A[r+1] < A[1],如果是插入排序,那么要比较r次,并且移动r个数据,
才能为A[r+1]腾出位置,但是如果用希尔排序,那么A[r+1]会跳跃式前进,而移动数据的次数也小于r次,这也是为什么希尔排序的效率高于插入排序的原因。
算法逻辑:
nStep = n / 2;
WHILE(nStep >= 1)
ShellSingleStepSort(pSrcData, nDataSize, nStep); //按照某个步长,进行一次排序
nStep = nStep / 2;
END FOR
对于单步排序,其实就是一个插入排序,但是该数据在数组中不是连续的,而是具有一定的间隔,也就是步长。
ShellSingleStepSort
输入:数组指针A, 数据大小size,步长step
输出:每个步长间隔的小序列都有序的数组
FOR I = step to size-1
curVal = A[I]
FOR J = i - step; j >= 0; j=-step //就是一个插入排序
IF A[J] > curVal THEN
A[J+step] = A[J]
ELSE
BREAK;
END IF
END FOR
A[J+step] = curVal
END FOR
算法实现
void ShellSingleStepSort(int* pSrcData, int nDataSize, int nStep)
{
for (int j= nStep; j < nDataSize; j++)
{
int nTmp = pSrcData[j];
int m = j - nStep;
for ( ; m >= 0; m -= nStep)
{
if (pSrcData[m] > nTmp)
pSrcData[m + nStep] = pSrcData[m];
else
break;
}
if (j != m + nStep)
pSrcData[m+nStep] = nTmp;
}
}
//步长为:DataSize/2, DataSize/4, DataSize/8......1
void ShellSort(int* pSrcData, int nDataSize)
{
int nStep = nDataSize / 2;
while (nStep >= 1)
{
ShellSingleStepSort(pSrcData, nDataSize, nStep);
nStep = nStep / 2;
}
}
排序结果比较:
明显可以看出希尔排序的比较次数小于插入排序 数据规模 | InserationSort | ShellSort |
100 | 2478 | 2211 |
500 | 63750 | 48099 |
1000 | 251094 | 189171 |
5000 | 6305769 | 4379758 |
10000 | 24953116 | 17153512 |
50000 | 624724636 | 510011290 |