希尔排序

希尔排序

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n^2)的第一批算法之一

基本思想

希尔排序的基本思想是:现将待排序的数组分成多个待排序的子序列,使得每个子序列的元素较少,然后对各个子序列分别进行插入排序,待到整个待排序的序列基本有序的时候,最后在对所有的元素进行一次插入排序。
希尔排序的具体步骤如下:

  • 选择一个步长序列t1,t2,t3,···,tk, 满足tm>tn(m < n), tk = 1
  • 按照步长序列个数,对待排序序列进行k趟排序
  • 每趟排序根据对应的步长,将待排序序列分割成若干个子序列,分别对这些子序列进行插入排序

我们选择的步长是一个缩小增量序列,通常情况下选择的步长为gap=length/2,缩小增量继续以gap=gap/2的方式,直到增量最后变成1,即{n/2,(n/2)/2...1}。希尔排序的增量序列的选择是一个数学难题,通常选取这个常用的增量序列。下图示例了希尔排序的过程:
shell_sort

代码实现

/**
 * ShellSort
 */
import java.util.Arrays;
public class ShellSort {
    /**
     *  希尔排序 针对有序序列在插入时采用交换法
     */
    public static void shellSort(int[] array) {
        int len = array.length;
        if (len <= 0) {
            return;
        }
        //初始化步长
        int gap = len>>1;
        //循环控制缩小步长
        for (; gap >= 1; gap >>= 1) {
            //从第gap个元素,逐个对其所在组的元素进行插入排序
            for (int i = gap; i < len; i++) {
                int j = i;
                while (j-gap>=0 && array[j] < array[j-gap]) {
                    swap(array, j, j-gap);
                    j -= gap;
                }
            }
        }
    }

    /**
     *  希尔排序 针对有序序列在插入时采用移动法
     */
    public static void shellSortS(int[] array) {
        int len = array.length;
        if (len <= 0) {
            return;
        }
        int gap = len>>1;
        for (; gap >= 1; gap >>= 1) {
            for (int i = gap; i < len; i++) {
                int j = i;
                int tmp = array[j];
                while (j-gap>=0 && array[j] < array[j-gap]) {
                    array[j] = array[j-gap];
                    j -= gap;
                }
                array[j] = tmp;
            }
        }
    }
    public static void swap(int[] array, int pos1, int pos2){
        int tmp = array[pos1];
        array[pos1] = array[pos2];
        array[pos2] = tmp;
    }

    
    public static void main(String []args){
        int []arr ={1,4,2,7,9,8,3,6};
        shellSort(arr);
        System.out.println(Arrays.toString(arr));
        int []arr1 ={1,4,2,7,9,8,3,6};
        shellSortS(arr1);
        System.out.println(Arrays.toString(arr1));
    }
}

复杂度及稳定性

希尔排序时间复杂度
希尔排序的时间复杂度与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量{1, 3, ..., 2^k-1}的希尔排序的时间复杂度为O(N3/2)。
希尔排序稳定性
希尔排序是不稳定的算法,它满足稳定算法的定义。对于相同的两个数,可能由于分在不同的组中而导致它们的顺序发生变化。

算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

posted @ 2018-07-10 14:05  流泉滴沙  阅读(166)  评论(0编辑  收藏  举报