本文对于希尔排序的实现有两种细节不同的方式:
希尔排序中的部分代码和直接插入排序类似,直接插入排序是增量d为1的特例。
直接插入排序跳转
区分子列单独处理
void shellSort1(int a[],int n){
//设置起始增量为数组长度的一半
for(d=n/2;d>=1;d/=2){
//m为子列的数量
if(n%d==0){
m=n/d;
}
else{
m=n/d+1;
}
//wh确定当前操作的是第几个子列
for(wh=0;wh<m;wh++){
//这里i的初值是当前子列中的第二个元素
//i每次+d,在同一个子列操作
for(i=d+wh;i<n;i+=d){
//往后和直接插入排序是一样的,只是直接插入排序中d为1
if(a[i]<a[i-d]){
temp=a[i];
for(j=i-d;j>=0&&a[j]>temp;j-=d){
a[j+d]=a[j];
}
a[j+d]=temp;
}
}
}
}
}
按数组顺序轮流子列处理
void shellSort2(int a[],int n){
for(d=n/2;d>=1;d/=2){
//注意对比,这里的i每次+1,是不区分子列,依次对数组进行排序
for(i=d;i<n;i++){
if(a[i]<a[i-d]){
temp=a[i];
for(j=i-d;j>=0&&a[j]>temp;j-=d){
a[j+d]=a[j];
}
a[j+d]=temp;
}
}
}
}
运行代码
//设置不同的增量,排序趟数以及在每趟中各个元素对比和移动次数也不同
//最坏时间复杂度:O(n^2),当n在某个范围内,可达O(n^1.3)
//不稳定排序算法,仅适用于顺序表
#include <iostream>
using namespace std;
int i,j;
int temp; //存放当前元素
int d; //增量
int m; //以当前增量作为分割,m为子列的数量
int wh; //wh确定当前操作的是第几个子列
//这里的是单独对每个子列进行操作
void shellSort1(int a[],int n){
//设置起始增量为数组长度的一半
for(d=n/2;d>=1;d/=2){
//m为子列的数量
if(n%d==0){
m=n/d;
}
else{
m=n/d+1;
}
//wh确定当前操作的是第几个子列
for(wh=0;wh<m;wh++){
//这里i的初值是当前子列中的第二个元素
//i每次+d,在同一个子列操作
for(i=d+wh;i<n;i+=d){
//往后和直接插入排序是一样的,只是直接插入排序中d为1
if(a[i]<a[i-d]){
temp=a[i];
for(j=i-d;j>=0&&a[j]>temp;j-=d){
a[j+d]=a[j];
}
a[j+d]=temp;
}
}
}
}
}
//这里是依次对数组元素操作,不分是哪个子列
void shellSort2(int a[],int n){
for(d=n/2;d>=1;d/=2){
//注意对比,这里的i每次+1,是不区分子列,依次对数组进行排序
for(i=d;i<n;i++){
if(a[i]<a[i-d]){
temp=a[i];
for(j=i-d;j>=0&&a[j]>temp;j-=d){
a[j+d]=a[j];
}
a[j+d]=temp;
}
}
}
}
//输出
void out(int a[],int n){
for(int i=0;i<n;i++){
cout<<a[i]<<" ";
}
}
int main(){
int a[]={53,13,29,1,5,99,76,38};
int n=sizeof(a)/sizeof(int);
shellSort2(a,n);
out(a,n);
return 0;
}