希尔排序

  希尔排序也是一种插入排序,不过,它在进行比较和交换位置的时候,不是相邻元素之间的比较,而是具有一定的间隔之间的元素进行比较。这个间隔是多少呢?一般刚开始排序的时候,是数组长度的1/2. 比如有一个长度是13的数组,那么间隔是13/2,就是6.  比较的时候,由于是插入排序,它是间隔索引后面的元素和间隔索引前面的元素进行比较,索引6处的元素与索引0处的元素进行比较,索引7处的元素和索引1处的元素进行比较,索引8处的元素和索引2处元素地进行比较,索引9处的元素和索引3处元素地进行比较,索引10处的元素和索引4处元素地进行比较,索引11处的元素和索引5处元素地进行比较,索引12处的元素和索引6处元素地进行比较,由于索引6和索引0是一个间隔,所以索引12和索引6的元素比较完了以后,还要和索引0处的元素进行比较。相同间隔的元素进行比较,[0, 6, 12]进行比较,[1, 7]进行比较,还有[2, 8], [3, 9], [4, 10], [5, 11], 也可以说,间隔把数组分了子数组,在子数组中进行插入排序。

   在各个子数组中,执行比较和位置交换

   执行完一轮排序后,第二次进行排序时,间隔是数组的长度/4, 也就是13/4, 等于3,这也就意味着,索引3和索引0进行比较,索引4和索引1进行比较,索引5和索引2,索引6和索引3,然后再和索引0,依次类推

  在相应的子数组中实现比较和和位置交换

   再进行一次,间隔是数组的长度/8,也就是13/8,等于1,间隔是1,也就没有必要再分子数组了,直接对整个数组来一次插入排序。如要数组的长度是N,那么问隔的选取依次是N/2, N/4, N/8 ....  直到1,每一次都是原来的1/2.

  对于希尔排序来说,首先是间隔的循环,假设数组的长度为N

for(int interval = N/2;  interval > 0;  interval /=2){}

  获取到间隔后,间隔后的元素要和间隔前的元素进行比较,假设数组是arr, 那就arr[interval], arr[interval +1], arr[interval + 2], 从inteval开始,依次取出数组的元素,这又是一个循环

// 从interval 开始,依次取出数组中的元素
for (int i = interval; i < n ; i++) {
    int temp = arr[i];
}

  获取到元素后,要和 i -  interval处的元素进行比较,像[0, 6, 12], 6处的元素和0进行比较,正好相差inteval。但就像[0, 6, 12]一样,索引12处的元素要和索引6处的元素进行比较,还要和索引0处元素进行比较,相当于i-和i -  interval, 再和 i -  interval- interval, 如果在比较程中有不符合排序顺序,就交换位置。这也是一个循环,把i赋值为j,以interval进行递减,结束条件是j>= interval, 因为j -interval 要大于0,数组元素的索引要大于0.

int j;
// 取出的元素和前面interval处的元素进行比较
for (j = i; j >= interval && (arr[j - interval] > temp); j -= interval) {
    // 如果前面的数比后面的大,前面的数赋值给后面的数
    arr[j] = arr[j - interval];
}

// 循环完毕后,如果位置有移动,j的位置就是temp的位置
arr[j] = temp;

  整个排序如下

import java.util.Arrays;

class ArraySort {
    public static void shellSort(int[] arr, int n) {
        for (int interval = n / 2; interval > 0; interval /= 2) {
            // 从interval 开始递增,循环
            for (int i = interval; i < n; i++) {
                // 依次取出数组中的元素
                int temp = arr[i];

                int j;
                // 取出的元素和前面interval处的元素进行比较
                for (j = i; j >= interval && (arr[j - interval] > temp); j -= interval) {
                    // 如果前面的数比后面的大,前面的数赋值给后面的数
                    arr[j] = arr[j - interval];
                }

                // 循环完毕后,如果位置有移动,j的位置就是temp的位置
                arr[j] = temp;
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {10, 16, 11, 4, 15, 3, 9, 6, 1, 17, 8, 12, 7};
        shellSort(arr, arr.length);
        System.out.println(Arrays.toString(arr));
    }

}

 

posted @ 2022-02-09 17:29  SamWeb  阅读(44)  评论(0编辑  收藏  举报