前面说过插入排序,插入排序是三种基本排序中较快的一种,效率最低的是冒泡排序,因为冒泡排序需要反复比较。对于插入排序虽然较快,不过比较复制次数比较多。希尔排序是在插入排序的基础上进行改进,排序速度比插入排序要快。
希尔排序是通过缩小插入排序中的元素之间的间隔,假设是对数组进行排序,可以认为希尔排序首先将对数组进行划分子数组,对每个数组进行插入排序。子数组的划分依据是每个一定的长度h。通过缩短h来减少子数组的数量。最终使子数组数量变为一个,再进行一次插入排序。这种排序的方式也需要对整个数组进行一次插入排序,但是由于之前子数组通过排序后已经避免了插入排序的最坏情况。最后一次插入排序能够减少大规模的复制操作。接下来使用图例说明这个过程:
假设初始数组长度是10。第一个划分数组可以有5个子数组。
![这里写图片描述](https://img-blog.csdn.net/20160910182401557)
分别对A B C D E五个子数组进行插入排序后得到的数组为:
![这里写图片描述](https://img-blog.csdn.net/20160910182547450)
以上对子数组进行排序实现了“基本有序”。接下来继续划分子数组,h=h/2=2;将数组分为2个。继续对着两个子数组进行插入排序。
![这里写图片描述](https://img-blog.csdn.net/20160910182849502)
通过以上对A B子数组进行排序以后A数组有序、B数组有序。接下来只需要划分一次,对一个数组进行排序即可。
第三次划分 h=1,对一个数组进行插入排序
![这里写图片描述](https://img-blog.csdn.net/20160910183430083)
这样就实现了对一个数组的希尔排序。以下是希尔排序的代码:
public void shellSort()
{
h=arr.length;
int m=0;
while(true)
{
h=h/2;
for(int i=0;i<h;i++)
{
for(int j=i+h;j<arr.length;j+=h)
{
int temp=arr[j];
for(m=j-h;m>=0&&arr[m]>temp;m=m-h)
{
arr[m+h]=arr[m];
}
arr[m+h]=temp;
}
}
if(1==h)
break;
}
}
以上在划分子数组对子数组进行排序可以选择常见的排序,目的在与交换数据项,由于插入排序是基本排序方法中较快,所以使用插入排序。
private int[] arr=null;
private int size=0;
private int h=0;
public ShellSort(int length)
{
arr=new int[length];
}
public void insert(int data)
{
arr[size++]=data;
h=size;
}
public void showArray()
{
for(int i=0;i<arr.length;i++)
{
System.out.print(arr[i]+" ");
}
System.out.println("");
}
测试及结果:
ShellSort a=new ShellSort(10);
a.insert(1);
a.insert(3);
a.insert(5);
a.insert(7);
a.insert(9);
a.insert(2);
a.insert(4);
a.insert(6);
a.insert(8);
a.insert(10);
a.showArray();
a.shellSort();
a.showArray();
1 3 5 7 9 2 4 6 8 10
1 2 3 4 5 6 7 8 9 10
关于希尔排序的效率
希尔排序的执行时间依赖于增量序列,时间性能优于直接插入排序,可以认为希尔排序是对插入排序的改进。