数组排序-希尔排序(Shell's Sort)
介绍:
希尔排序是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因Donald Shell于1959年提出而得名。
历史:
希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布。一些老版本教科书和参考手册把该算法命名为Shell-Metzner,即包含Marlene Metzner Norton 的名字,但是根据Metzner本人的说法:“我没有为这种算法做任何事,我的名字不应该出现在算法的名字中”。
希尔排序是基于插入排序的以下两点性值而提出改进方法的:
1.插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
2.但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
基本思想:
取一个小于n的整数d1作为一个增量,把文件的全部记录数组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2
比较相隔较远距离(增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。Donald Shell于1959年在以他的名字命名的派苏算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d,对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。
给定实例的shell排序的排序过程。
假设待排序的文件有10个记录,其关键字分别是:
86,11,54,34,53,12,45,81,19,65
增量序列的取值依次为:
5,2,1
稳定性:
由于多次插入排序,我们知道一次插入排序是不稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
排序过程:
缩小增量 运行结果: 优劣: 时间性能: 因此,希尔排序在效率上较直接插入排序有较大改进。
希尔排序属于插入类排序,是将整个有序序列分割成若干小的子序列分别进行插入排序。
排序过程:先取一个正整数d1
示例:
package com.lxj.cnblogs;
/**
* @author 刘小将
* 测试希尔排序
*/
public class ShellSort {
public static void main(String[] args) {
int[] a = {86,11,54,34,53,12,45,81,19,65}; //声明一个数组并给定值
printArray(a); //输出原始数组到控制台
int k = 3;
while (k >= 1){
shellSort(a,k);
printArray(a);
k--;
}
}
/**
* 希尔排序算法
* @param a
* @param k
*/
public static void shellSort(int[] a,int k){
int i = 0;
int j = 0;
for(i = k;i < a.length;i+=k){
int temp = a[i];
if(a[i-k]>a[i]){
for (j = i-k;j >= 0; j-=k){
if(temp86 11 54 34 53 12 45 81 19 65
34 11 54 45 53 12 65 81 19 86
19 11 34 45 53 12 54 81 65 86
11 12 19 34 45 53 54 65 81 86
原理:
算法分析:
不需要大量的辅助空间,和归并排序一样容易实现。希尔排序是基于插入排序的一种算法,在此基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n2),而Hibbard增量的希尔排序的时间复杂度为O(n(3/2)),希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法快O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(n^2)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都是都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法。本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少其复制的次数,速度要快很多,原因是:当n值很大时数据项每一趟排序需要的个数很少,但数据项的距离很长。当n值减小时每一趟需要和动的数据增多,此时已经接近于它们排序后的最终位置。正是这两种情况的结合才使希尔排序效率比插入排序高很多。Shell算法的性能与所选取的分组长度序列有很大的关系。只对特定的待排序记录序列,可以准确地估算关键词的比较次数和对象移动次数。想要弄清关键词比较次数和记录移动次数与增量选择之间的关系,并给出完整的数学解析,至今仍是数学难题。
1.增量序列的选择:
Shell排序的执行时间依赖于增量序列。
好的增量序列的共同特征:
a.最后一个增量必须为1。
b.应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
有人通过大量的实验,给出了较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。
2.Shell排序的时间性能优于直接插入排序:
希尔排序的时间性能优于直接插入排序的原因:
a.当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
b.当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度O(n2)差别不大。
c.在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减小,而各组的记录数数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。