通过选取适当的gap能将算法复杂度降低为O(n^(4/3)),不得不说希尔排序也是很棒滴。
/*
* szlShellSort.h
*/
#ifndef SZL_SHELLSORT_H
#define SZL_SHELLSORT_H
/*
* 希尔排序
*/
void shellSort(int a[], int n);
#endif
/*
* szlPower.h
*/
#ifndef SZL_POWER_H
#define SZL_POWER_H
/*
* 求a的b次方;b>=0
*/
int power(int a, int b);
#endif
/*
* szlShellSort.c
*/
#include "szlShellSort.h"
#include "szlSwap.h"
#include "szlPower.h"
//#define SZLP(fmt,args...) printf("%s,%d: "fmt"\n",__FUNCTION__,__LINE__,##args)
/*
* 希尔排序(缩小增量的插入排序算法);是直接插入排序的一个扩展的版本;
* 可将直接插入排序看成是间距为1的希尔排序;希尔排序的思想是,由于插入排序每次只能将
* 元素往前移动一个单位,所以效率可能比较低,希尔排序通过设置间距来保证每次可以移动
* 适当的单位,因此可能提高排序效率;
* 实践证明,当选取得间距gap的值较为合适时,算法的复杂度为O(n^1.3)及O(n*(lgn)^2)等比较
* 低的复杂度。
*/
void shellSort(int a[], int n){
int m=0,i,j,k,gap;
/*
* 这里只是选取一种常用的gap;其分析来自wiki;
* http://en.wikipedia.org/wiki/Shellsort
* 当gap=1+3*2^(k-1)+4^k时满足O(n^(4/3))的时间复杂度;
*/
do{
m++;
gap=1+3*power(2,m-1)+power(4,m);
}while(gap<n);
for(m--;m>=1;m--){
if(1==m){
gap = 1;
}
else{
gap = 1+3*power(2,m-1)+power(4,m);
}
for(i=0;i<gap;i++){ //gap为多大,数组就被切割为多少个子数组
for(j=i+gap;j<n;j+=gap){ //从每个子数组的下一个元素访问
k=j;
while(a[k]<a[k-gap]){ //将新近访问到的元素插入到自身的子数组中去
swap(&a[k],&a[k-gap]);
k-=gap;
if(k-gap<i){ //往前访问到第一个元素就要停止往前
break;
}
}
}
}
}
}
/*
* szlPower.c
*/
#include <assert.h>
#include "szlPower.h"
/*
* 求a的b次方
*/
int power(int a, int b){
assert(0<=b);
if(0==b){
return 1;
}
else if(1==b){
return a;
}
else{
return a*power(a,b-1);
}
}
下面是和其他算法的比较,输入的Inut SIZE是输入规模,程序自动生成一个如此大小的一维数组;当其他的算法需要等待很久时,我终止他们的运行。先看输入为1,000、10,000及100,000时的运行情况:
然后是输入为1,000,000及10,000,000的情形:
可以看到,希尔排序在大数据量时还是比较不错的,其运行时间(单位为毫秒)差不多和这些号称是NlgN的算法一样,而其他的基本排序算法(插入排序、选择排序、冒泡排序)几乎不可能运行出来。
当输入规模为100,000,000时,我的电脑已经不够分配空间了,呵呵,所以暂时就不跑了。