希尔排序

Posted 51life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了希尔排序相关的知识,希望对你有一定的参考价值。

在插入排序中,我们假设在即将进行排序的元素的左侧所有的元素已经是有序的,所以我们会将该元素与它左侧的元素逐个比较,如果左侧的元素大于该元素,则左侧的元素右移。然后,该元素继续与左侧的下一个元素比较。现在有一个问题:极端情况下,刚开始很小的元素放到了最右侧,那么它左侧所有的元素都要向右移动复制一次,这样效率是很低的,那么如何解决呢?可以考虑希尔排序。希尔排序是基于插入排序的,它通过加大插入排序中元素的间隔,从而使得元素能够大跨度的移动,这样能减少移动次数。经过一趟排序后,然后减小间隔再排序,直至最后一次排序的间隔为1,这最后一次的排序其实就是插入排序。这里,涉及到一个间隔h,一般情况下,我们使用h = 3*h+1。注意:颜色相同的元素都进行了排序。

情景:对数组 int[] arr = {7,10,1,9,2,5,8,6,4 ,3}中的数据 从小到大排序。

第一趟排序前:7   10   1   9   2   5   8   6   4   3     第一趟排序后:2   3     6   4   5     9     10       (h = 4)  

第二趟排序前:2   3   1   6   4   5   8   9   7   10     第二趟排序后:1   2   3   4   5   6   7   8   9   10        (h = 1)

代码:

/**
 * 希尔排序
 * @author D N
 *
 */
public class ShellSort {
    private long[] a; 
    private int nElems;
    
    public ShellSort(int max){
        a = new long[max];
        nElems = 0;
    }    
    
    public void insert(long value){
        a[nElems] = value;
        nElems++;
    }
    
    public void display(){
        for(int j=0;j<nElems;j++){
            System.out.print(a[j]+"   ");
        }
        System.out.println("");
    }
    
    
        //希尔排序算法 
        public void shellSort(){
            int inner,outer;
            long temp; // 临时变量
            
            int h = 1; //数据项之间的间隔,排序时按此间隔排序
            while(h <= nElems/3 ){
                h = h*3+1;
            }
            
            while(h > 0){ //不断减少h,直至h = 1,此时排序成为了插入排序
                for(outer = h;outer < nElems;outer++){
                    temp = a[outer];
                    inner = outer;
                    while(inner > h-1 && a[inner-h] >= temp){
                        a[inner] = a[inner-h];
                        inner -= h;
                    }
                    a[inner] = temp;
                }
                h = (h-1)/3;
                display();
            }
            
        }
}

运行测试代码:

public class SortTest {
    public static void main(String[] args) {
        int maxSize = 10;
        ShellSort arr = new ShellSort(maxSize);
        arr.insert(7);
        arr.insert(10);
        arr.insert(1);
        arr.insert(9);
        arr.insert(2);
        arr.insert(5);
        arr.insert(8);
        arr.insert(6);
        arr.insert(4);
        arr.insert(3);
        arr.display();
        System.out.println();
        arr.shellSort();
        System.out.println();
        arr.display();
    }
}

运行结果:

7   10   1   9   2   5   8   6   4   3   

2   3   1   6   4   5   8   9   7   10   
1   2   3   4   5   6   7   8   9   10   

1   2   3   4   5   6   7   8   9   10   

效率分析:

希尔排序效率比插入排序要高,在有几千个元素需要排序时,它的效率更容易显现出来。原因就是:当h大的时候,每一趟排序需要移动的元素个数很少,但是移动的距离很长,这很有效率。当h减少时,每一趟排序需要移动的次数增多,但是此时数组已经接近排序后最终的位置,当h=1时,希尔排序也就成为了插入排序。

以上是关于希尔排序的主要内容,如果未能解决你的问题,请参考以下文章

希尔排序

插入排序(直接插入排序折半插入排序希尔排序的算法思想及代码实现)

希尔排序图解与代码

算法-java代码实现希尔排序

希尔排序JAVA代码

《算法》笔记 3 - 选择排序插入排序希尔排序