希尔排序(Shell Sort)是
插入排序
的一种。是针对
直接插入排序
算法的改进。该方法又称缩小
增量
排序,因DL.Shell于1959年提出而得名。
先取一个小于n的整数d1作为第一个
增量
,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行
直接插入排序
;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止(即最后一趟为直接插入排序)。
测试:
结果:
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
1.插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
2.但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位
算法分析
1.增量序列的选择
Shell排序的执行时间依赖于增量序列。
好的增量序列的共同特征:
① 最后一个增量必须为1;
② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
有人通过大量的实验,给出了目前较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。
2.Shell排序的时间性能优于直接插入排序
希尔排序的时间性能优于直接插入排序的原因:
①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
②在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。
因此,希尔排序在效率上较直接插人排序有较大的改进。
3.稳定性
希尔排序是不稳定的。
实现:
//ader为增量
void ShellInsert(int arr[],int len,int ader)
{
if(arr == NULL || len <= 0 || ader <= 0)
{
return;
}
int i,j,temp;
for(i = ader; i < len; i++)
{
if(arr[i-ader] > arr[i])
{
temp = arr[i];
for(j = i-ader; j>=0 && temp < arr[j]; j-=ader)
{
arr[j+ader] = arr[j];
}
arr[j+ader] = temp;
}
}
}
//dlta为增量序列,t为增量序列的长度
void ShellSort(int arr[],int len,int dlta[],int t)
{
for(int i = 0; i < t; i++)
{
ShellInsert(arr,len,dlta[i]);//使用每个增量,进行直接插入排序
}
}
测试:
/****************************************
希尔排序
by Rowandjj
2014/7/19
****************************************/
#include<iostream>
using namespace std;
//ader为增量
void ShellInsert(int arr[],int len,int ader)
{
if(arr == NULL || len <= 0 || ader <= 0)
{
return;
}
int i,j,temp;
for(i = ader; i < len; i++)
{
if(arr[i-ader] > arr[i])
{
temp = arr[i];
for(j = i-ader; j>=0 && temp < arr[j]; j-=ader)
{
arr[j+ader] = arr[j];
}
arr[j+ader] = temp;
}
}
}
//dlta为增量序列,t为增量序列的长度
void ShellSort(int arr[],int len,int dlta[],int t)
{
for(int i = 0; i < t; i++)
{
ShellInsert(arr,len,dlta[i]);//使用每个增量,进行直接插入排序
}
}
int main()
{
int i;
int arr[] = {9,7,5,3,1,6,11,8,4};
int dlta[] = {5,3,1};
ShellSort(arr,9,dlta,3);
for(i = 0; i < 9; i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
return 0;
}
结果: