希尔排序(Shell's sort)是插入排序的一种 又称为“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是不稳定的排序算法。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量的逐渐减少,每组包含的关键字越来越多,当增量减少至1时,整个文件恰被分为一组,算法终止。
希尔排序是基于插入排序的一下两点性质而提出改进方法的:
1.插入排序在对几乎已经排好序的数据操作时,效率高,既可以达到线性排序的效率。
2.但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
一:基本思想
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组中进行直接插入排序;然后取第二个增量d2<d1重复上述的分组和排序,直至所取的增量d = 1,即所有的记录放在同一组中进行直接插入排序为止。
实质:分组插入方法
比较相隔较远距离(称为增量)的数,使得移动时能够跨越多个元素,则进行一次比较就可能消除多个元素的交换。
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。
二:演示过程
三:代码解析
#include<iostream>
using namespace std;
template<typename T>
void shellinsert(T arr[],int len,int grp)//O(n)
{
int i = grp;
int j = 0;
T tmp = T();
for(i=grp;i<len;++i)
{
tmp = arr[i];
for(j = i-grp;j>=0;j-=grp)
{
if(arr[j]>tmp)
{
arr[j+grp] = arr[j];
}
else
break;
}
arr[j+grp] = tmp;
}
}
template<typename T>
void shell(T arr[],int len)
{
for(int div = len/2;div>0;div/=2)//时间复杂度为O(log n)
shellinsert(arr,len,div);
}
int main()
{
int arr[] = {15,48,67,9,45,13,16,9,99,13};
int len = sizeof(arr)/sizeof(arr[0]);
shell1(arr,len);
for(int i= 0;i<len;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
return 0;
}
四:稳定性分析
由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
五:时间复杂度
算法的平均复杂度为 O(n^1.3),算法的最坏的时间复杂度为O(n^2),最好的时间复杂度为O(n),空间复杂度为O(1)。
六:算法分析
不需要大量的辅助空间,希尔排序是基于插入排序的一种算法,在此算法之上增加了新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量的时间复杂度为O(n^2),而Hibbard增量的希尔排序的时间复杂度为O(n^1.5),当数据量相当大的时间,其算法的效率不如快排快,因此中等大小的数据量适用于希尔排序,希尔排序在最坏和平均的情况下执行效率差不多,而快速排序的最坏和平均的情况下其相差比较大,所以,几乎任何排序工作在开始时都可以用希尔排序,如果在实际中,其速度不能满足我们的要求我们在使用快排。
shell算法的性能与所选取的分组长度序列有关。