希尔排序分析及代码实现

6.6 希尔排序

6.6.1 插入排序的问题所在

对于插入排序存在一个问题: 如果待排序列前面的数据已经有序,而恰巧靠后的数字又比较小,后面的数据就要一直比较到最前面,这样需要比较的次数比较多;
希尔排序解决这一问题: 把整个待排序列进行增量分组,对每组使用插入排序算法,没排序完,使得增量减半,随着增量的逐渐减小至1,整个数组被分成一组进行排序,而此时大部分数据已经处于有序位置,
即使无序数据也离正确的位置不远,比较次数少。

6.6.2 希尔排序的思想

插入排序时比较相邻的元素大小,进行插入,希尔排序是在插入排序的基础上,对所有待排序以一个间隔进行插入排序,间隔gap的初始化值可以设置为数组长度的一半,每当一轮以gap为单位的插入排序结束之后,减小gap的值,直至gap等于1,此时最后一轮排序时,整个数组的大部分元素已经处于有序位置,进行最后一轮插入排序。可以理解为希尔排序是在插入排序的基础上进行的。

6.6.3 希尔排序示意图

在这里插入图片描述
在这里插入图片描述

6.6.4 代码分析:
package com.kevin.sortAlgorithm;
import java.util.Arrays;

/**
 * @author : kevin ding
 * @date : 2022/3/3 21:47
 * @description :   对于插入排序存在一个问题: 如果待排序列前面的数据已经有序,而恰巧靠后的数字又比较小,后面的数据就要一直比较到最前面,这样需要比较的次数比较多;希尔排序解决这一问题: 把整个待排序列进行增量分组,对每组使用插入排序算法,没排序完,使得增量减半,随着增量的逐渐减小至1,整个数组被分成一组进行排序,而此时大部分数据已经处于有序位置,即使无序数据也离正确的位置不远,比较次数少
 */
public class ShellSortDemo {
    public static void main(String[] args) {
        // int[] array = {8,9,1,7,2,3,5,4,6,0};
        // System.out.println("排序之前,结果为:");
        // System.out.println(Arrays.toString(array));
        // // shellSortAnalysis(array);
        // shellSort(array);

        // 对于  100000个数据进行排序,求其时间
        int[] array = new int[80000];
        for (int i = 0; i < array.length; i++) {
            array[i] = (int) (Math.random() * 8000000);
        }

        Long startTime = System.currentTimeMillis();
        shellSort(array);
        Long endTime = System.currentTimeMillis();

        System.out.println("希尔排序 所耗费的时间是:" + (endTime-startTime) + "ms");       // 12ms

    }

    public static void shellSortAnalysis(int[] array){
        // 对于一组数据,首先指定增量初始值为数组长度的一半 gap = 10/2 =5;
        // 下标分组情况为 0,5; 1 6; 2 7; 3 8;  4 9 对这5组数据分别进行插入排序

        // int temp;   // 临时变量用于数据交换
        int insertValue;
        int insertIndex;
        // 第一轮排序:将10个数据分成了5组 需要遍历从gap之后的数 步长为gap
        int gap = 5;
        // 从 array[gap]到array[n-1]的元素为带插入元素,前面的有序元素为分组
        for(int i=gap; i<array.length; i++){
            //
            insertIndex = i;
            insertValue = array[i];
            // 此时需要进行比较的元素是与insertIndex相差gap的一个元素  比前一个gap的元素小,则需要进行交换
            // 若insertIndex小于gap了,则说明其前面没有相距gap的值了,已经处于了这组中合适的位置
            while(insertIndex >=gap && array[insertIndex - gap] > insertValue){
                // 需要进行交换
                array[insertIndex] = array[insertIndex- gap];
                array[insertIndex-gap] = insertValue;
                insertIndex -= gap;
            }

        }
        System.out.println("第1 轮shell排序之后:");
        System.out.println(Arrays.toString(array));

        // 第2轮排序:将10个数据分成了5/2 = 2组 需要遍历从gap之后的数 步长为gap
        gap = 2;
        // 从 array[gap]到array[n-1]的元素为带插入元素,前面的有序元素为分组
        for(int i=gap; i<array.length; i++){
            //
            insertIndex = i;
            insertValue = array[i];
            // 此时需要进行比较的元素是与insertIndex相差gap的一个元素  比前一个gap的元素小,则需要进行交换
            // 若insertIndex小于gap了,则说明其前面没有相距gap的值了,已经处于了这组中合适的位置
            while(insertIndex >=gap && array[insertIndex - gap] > insertValue){
                // 需要进行交换
                array[insertIndex] = array[insertIndex- gap];
                array[insertIndex-gap] = insertValue;
                insertIndex -= gap;
            }

        }
        System.out.println("第1 轮shell排序之后:");
        System.out.println(Arrays.toString(array));


        // 第3轮排序:将10个数据分成了2/2 = 1组 需要遍历从gap之后的数 步长为gap
        gap = 1;
        // 从 array[gap]到array[n-1]的元素为带插入元素,前面的有序元素为分组
        for(int i=gap; i<array.length; i++){
            //
            insertIndex = i;
            insertValue = array[i];
            // 此时需要进行比较的元素是与insertIndex相差gap的一个元素  比前一个gap的元素小,则需要进行交换
            // 若insertIndex小于gap了,则说明其前面没有相距gap的值了,已经处于了这组中合适的位置
            while(insertIndex >=gap && array[insertIndex - gap] > insertValue){
                // 需要进行交换
                array[insertIndex] = array[insertIndex- gap];
                array[insertIndex-gap] = insertValue;
                insertIndex -= gap;
            }

        }
        System.out.println("第1 轮shell排序之后:");
        System.out.println(Arrays.toString(array));
    }

}

6.6.5 代码实现:
public static void shellSort(int[] array){
        // 上述的逐次过程中,只有gap在发生变化,可以进行循环
        // 定义待比较元素值 和 该元素合适的位置索引
        int insertValue;
        int insertIndex;
        int count = 0;
        // 第一轮排序:将10个数据分成了5组 需要遍历从gap之后的数 步长为gap
        int gap = array.length / 2;
        while(gap > 0){
            // 从 array[gap]到array[n-1]的元素为带插入元素,前面的有序元素为分组
            for(int i=gap; i<array.length; i++){
                //
                insertIndex = i;
                insertValue = array[i];
                // 此时需要进行比较的元素是与insertIndex相差gap的一个元素  比前一个gap的元素小,则需要进行交换
                // 若insertIndex小于gap了,则说明其前面没有相距gap的值了,已经处于了这组中合适的位置
                while(insertIndex >=gap && array[insertIndex - gap] > insertValue){
                    // 需要进行交换
                    array[insertIndex] = array[insertIndex- gap];
                    array[insertIndex-gap] = insertValue;
                    insertIndex -= gap;
                }
            }
            // 一轮循环结束,gap的值减半
            gap /= 2;
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是C语言实现简单插入排序、希尔排序和基数排序的示例代码,同时还包括了对三种排序算法的比较分析。 ## 简单插入排序 ```c void insertionSort(int arr[], int n) { int i, j, key; for (i = 1; i < n; i++) { key = arr[i]; j = i - 1; while (j >= 0 && arr[j] > key) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = key; } } ``` 简单插入排序的时间复杂度为O(n^2)。 ## 希尔排序 ```c void shellSort(int arr[], int n) { int gap, i, j, temp; for (gap = n / 2; gap > 0; gap /= 2) { for (i = gap; i < n; i++) { temp = arr[i]; for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap) { arr[j + gap] = arr[j]; } arr[j + gap] = temp; } } } ``` 希尔排序的时间复杂度为O(n log n)。 ## 基数排序 ```c void radixSort(int arr[], int n) { int i, j, m = arr[0], exp = 1; int *bucket = (int *) malloc(sizeof(int) * n); for (i = 0; i < n; i++) { if (arr[i] > m) { m = arr[i]; } } while (m / exp > 0) { int bucketCnt[10] = {0}; for (i = 0; i < n; i++) { bucketCnt[arr[i] / exp % 10]++; } for (i = 1; i < 10; i++) { bucketCnt[i] += bucketCnt[i - 1]; } for (i = n - 1; i >= 0; i--) { bucket[--bucketCnt[arr[i] / exp % 10]] = arr[i]; } for (i = 0; i < n; i++) { arr[i] = bucket[i]; } exp *= 10; } free(bucket); } ``` 基数排序的时间复杂度为O(nk),其中k为最大数的位数。 ## 比较分析 简单插入排序和希尔排序都是基于比较的排序算法,而基数排序则是一种非比较排序算法。在排序效率方面,基数排序明显优于简单插入排序和希尔排序。同时,在数据规模较大时,基数排序的优势更加明显。不过需要注意的是,基数排序对数据的要求较高,比如需要数据是非负整数,并且最大值的位数不超过某个范围。 另外,希尔排序的时间复杂度与其增量序列的选取有关。对于一些特定的增量序列,希尔排序的效率可能会更高。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值