希儿排序

基本思想

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量        数据结构和算法-010 数组排序 希儿排序_ Java=1(        数据结构和算法-010 数组排序 希儿排序_数组_02<        数据结构和算法-010 数组排序 希儿排序_ Java_03…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

该方法实质上是一种分组插入方法

比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[2] 较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。

一般的初次取序列的一半为增量,以后每次减半,直到增量为1。


稳定性

由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。


算法分析

优劣

不需要大量的辅助空间,和归并排序一样容易实现。希尔排序是基于插入排序的一种算法, 在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n),而Hibbard增量的希尔排序的时间复杂度为O(

        数据结构和算法-010 数组排序 希儿排序_数组_04

),希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(

        数据结构和算法-010 数组排序 希儿排序_ Java_05

)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开 始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法. 本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当n值很大时数据项每一趟排序需要的个数很少,但数据项的距离很长。当n值减小时每一趟需要和动的数据增多,此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比插入排序高很多。Shell算法的性能与所选取的分组长度序列有很大关系。只对特定的待排序记录序列,可以准确地估算关键词的比较次数和对象移动次数。想要弄清关键词比较次数和记录移动次数与增量选择之间的关系,并给出完整的数学分析,至今仍然是数学难题。

时间性能

1.增量序列的选择

Shell排序的执行时间依赖于增量序列。

好的增量序列的共同特征:

① 最后一个增量必须为1;

② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。

有人通过大量的实验,给出了较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。

2.Shell排序的时间性能优于直接插入排序

希尔排序的时间性能优于直接插入排序的原因:

①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。

②当n值较小时,n和

        数据结构和算法-010 数组排序 希儿排序_ Java_05

的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(

        数据结构和算法-010 数组排序 希儿排序_ Java_05

)差别不大。

③在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。

因此,希尔排序在效率上较直接插入排序有较大的改进。


Note:参考百度百科 http://baike.baidu.com/link?url=cj20UNNK9PWLdROFrlFfEB1jJ522BjBcp6YlMdNDYIEBptKkEo8UJ9xurUf53n5XZJkNinVKBjaSZaAAR9ng5K


看代码,再慢慢分析吧。

public class ShellSort {

    private int[] theArray;
    private int arraySize;

    public ShellSort(int arraySize) {
        this.arraySize = arraySize;
        theArray = new int[arraySize];
        generateRandomArray();
    }

    public void generateRandomArray() {
        for (int i = 0; i < arraySize; i++) {
            theArray[i] = (int) (Math.random() * 50 + 10);
        }
    }

    public void printArray() {
        StringBuffer sb = new StringBuffer("-");
        for (int i = 0; i<arraySize; i++){
            sb.append("-----");
        }
        
        String septalLine= sb.toString();
        
        System.out.println(septalLine);
        for (int i = 0; i<arraySize; i++){
            System.out.print("|  " + i + " ");
        }
        System.out.println("|");
        System.out.println(septalLine);
        for (int i = 0; i<arraySize; i++){
            System.out.print("| " + theArray[i] + " ");
        }
        System.out.println("|");
        System.out.println(septalLine);
    }

    public void sort() {

        int inner, outer, temp;
        int interval = 1;

        while (interval <= arraySize / 3) {
            interval = interval * 3 + 1;
        }
        
        
        while (interval > 0) {

            System.out.println();
            System.out.println("Interval: " + interval);

            for (outer = interval; outer < arraySize; outer++) {
                temp = theArray[outer];
                System.out
                        .println("Copy " + theArray[outer] + " Into Temp");

                inner = outer;
                System.out.println("Check if " + theArray[inner - interval]
                        + " in index " + (inner - interval)
                        + " is greater than " + temp);
                
                while (inner > interval -1 && theArray[inner-interval]>= temp){
                    theArray[inner]= theArray[inner-interval];
                    inner = inner- interval;
                }
                theArray[inner]= temp;
                System.out.println("Save Temp " + temp + " into index " + inner );
                
                
            }
            System.out.println(Arrays.toString(theArray));
            interval= (interval-1)/3;
        }
    }

    public static void main(String[] args) {
        System.out.println("Create an array, and fill in random value");
        ShellSort ss = new ShellSort(10);
        ss.printArray();
        ss.sort();
        ss.printArray();
    }

}


希儿排序的理论就是那样,具体实现还是不一样的,这里用的是n=n*3+1, n的初始值是1,直到得到第一个大于总长度的第一个1/3的值。

        while (interval <= arraySize / 3) {
            interval = interval * 3 + 1;
        }

举例,如果数组长度是10,那最大分组值为4. 如果数组长度是100,那最大分组值为40. 1*3+1=4, 4*3+1=13, 13*3+1=40

下一次分组就是 (n-1)/3,以此往复。


分组比较的代码如下

while (inner > interval -1 && theArray[inner-interval]>= temp){
    theArray[inner]= theArray[inner-interval];
    inner = inner- interval;
}                }


输出结果

---------------------------------------------------
|  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 |
---------------------------------------------------
| 12 | 52 | 50 | 55 | 22 | 45 | 16 | 21 | 41 | 23 |
---------------------------------------------------

Interval: 4
Copy 22 Into Temp
Check if 12 in index 0 is greater than 22
Save Temp 22 into index 4
Copy 45 Into Temp
Check if 52 in index 1 is greater than 45
Save Temp 45 into index 1
Copy 16 Into Temp
Check if 50 in index 2 is greater than 16
Save Temp 16 into index 2
Copy 21 Into Temp
Check if 55 in index 3 is greater than 21
Save Temp 21 into index 3
Copy 41 Into Temp
Check if 22 in index 4 is greater than 41
Save Temp 41 into index 8
Copy 23 Into Temp
Check if 52 in index 5 is greater than 23
Save Temp 23 into index 1
[12, 23, 16, 21, 22, 45, 50, 55, 41, 52]

Interval: 1
Copy 23 Into Temp
Check if 12 in index 0 is greater than 23
Save Temp 23 into index 1
Copy 16 Into Temp
Check if 23 in index 1 is greater than 16
Save Temp 16 into index 1
Copy 21 Into Temp
Check if 23 in index 2 is greater than 21
Save Temp 21 into index 2
Copy 22 Into Temp
Check if 23 in index 3 is greater than 22
Save Temp 22 into index 3
Copy 45 Into Temp
Check if 23 in index 4 is greater than 45
Save Temp 45 into index 5
Copy 50 Into Temp
Check if 45 in index 5 is greater than 50
Save Temp 50 into index 6
Copy 55 Into Temp
Check if 50 in index 6 is greater than 55
Save Temp 55 into index 7
Copy 41 Into Temp
Check if 55 in index 7 is greater than 41
Save Temp 41 into index 5
Copy 52 Into Temp
Check if 55 in index 8 is greater than 52
Save Temp 52 into index 8
[12, 16, 21, 22, 23, 41, 45, 50, 52, 55]
---------------------------------------------------
|  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 |
---------------------------------------------------
| 12 | 16 | 21 | 22 | 23 | 41 | 45 | 50 | 52 | 55 |
---------------------------------------------------