算法与数据结构(五)--希尔排序

来源:互联网 发布:php调用python 编辑:程序博客网 时间:2024/06/05 07:52

希尔排序又称为“缩小增量排序”,是一种插入排序算法,是对直接插入排序的一种改进。

思想:

先按照一定的顺序跳着选元素序列进行插入排序,直到整个序列基本有序,再完整地调用一次插入排序。因为前面是跳着选元素的,就是按照一定的增量进行挑选元素,并且,这个增量是逐渐减小的,由于是跳着选的,所以,元素移动地速度就要比直接插入排序来得快,算法的时间复杂度也会明显降低。这里要注意,所取的增量序列中出了最后一个“1”以外,其他数必须是互质的,并且是按降序排列的。为什么呢?如果不是互质,就会出现都某个位置的数重复排序,这是没有必要的。

分解:

对于每一个增量n,原序列被拆分成n个序列:

(a[1] a[n+1] a[2n+1]...)

(a[2] a[n+2] a[2n+2]...) 

(a[3] a[n+3] a[2n+3]...) 

...

(a[n]a[2n] a[3n]...) 

而上面的每一个序列的排序过程又可以拆分成依次插入排序2个、3个、4个的形式。

(a[1]a[n+1] ) (a[1]a[n+1] a[2n+1] )(a[1] a[n+1] a[2n+1] ...)

(a[2] a[n+2] (a[2]a[n+2] a[2n+2] ) (a[2]a[n+2] a[2n+2] ...)

(a[3] a[n+3] )  (a[3] a[n+3] a[2n+3] ) (a[3]a[n+3] a[2n+3] ...)

...

(a[n]a[2n] (a[n-1]a[2n-1]a[3n])   (a[n-1]a[2n-1]a[3n]...) 

那么,仔细观察上述结构可以发现,上面每个序列的最后一个元素的下标按照从上到下、从左往右的顺序看,是连续的。那么,为了编程实现的方便,对于每一个n,我们都是从a[n+1]开始,一直到数组结束a[end,]找出前面与其间隔n个所有元素进行插入排序即可。这样,就可以很好的简化了整个排序过程的实现。


小插曲:

写代码的时候,一开始是打算传递整个数组进去,以int a[]作为形参,但是,发现,这样必须在返回一个数组作为返回参数。这样子的话,每执行一次,还要将返回值进行

复制到a[],会有额外的开销,所以,考虑使用数组的引用。一开始写成int &a[],一运行,报错了。查了下《C++ Primer》,下标操作比引用具有更高的优先级,所以要在前面加括号,并且必须指定数组的个数,就是写成int  (&a)[11]。但是,这样写似乎太过死板了,以后代码就只能够是用于10个数的排序了。怎么办?

最后,发现的利器是模板。就是将数组的元素个数以模板形式传入,这样,这个参数既是指定的,又是可以根据函数的实际调用情况来确定,真的很巧妙。

下面是代码实现:


#include <iostream>using namespace std;template<size_t N> void ShellInsert(int (&a)[N],int dk)//希尔插入排序过程{int alength = sizeof(a)/sizeof(a[0])-1;for (int i= dk+1;i<=alength;i++){if (a[i]<a[i-dk]){a[0] = a[i];    int j;for ( j=i-dk;j>0&&a[0]<a[j];j-=dk){a[j+dk] = a[j];}a[j+dk] = a[0];}}}template<size_t N> void ShellSort(int (&a)[N],int dklist[],int listlen){for (int i=0;i<listlen;i++){ShellInsert(a,dklist[i]);}}void main(){int a[] ={0,2,5,6,9,8,4,3,1,6,0};//a[0] 是哨兵int dklist[] = {5,3,1};ShellSort(a,dklist,3);for (int i = 1;i<11;i++){cout<<a[i]<<endl;}}

当然,也可以用直接传入一个指针的形式来传入参数的,就是int *a。
#include <iostream>using namespace std;void ShellInsert(int *a,int dk,int alength)//希尔插入排序过程{//int alength = 10;//sizeof(a)/sizeof(a[0])-1;for (int i= dk+1;i<=alength;i++){if (a[i]<a[i-dk]){a[0] = a[i];int j;for ( j=i-dk;j>0&&a[0]<a[j];j-=dk){a[j+dk] = a[j];}a[j+dk] = a[0];}}}void ShellSort(int *a,int alength,int dklist[],int listlen){for (int i=0;i<listlen;i++){ShellInsert(a,dklist[i],alength);}}void main(){int a[] ={0,2,5,6,9,8,4,3,1,6,0};//a[0] 是哨兵int dklist[] = {5,3,1};ShellSort(a,10,dklist,3);for (int i = 1;i<11;i++){cout<<a[i]<<endl;}}






0 0
原创粉丝点击