希尔排序笔记

Posted 是渣渣呀

tags:

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

希尔排序(算法)

基本介绍

简单插入排序存在的问题:

我们看简单的插入排序可能存在的问题.
数组 arr = 2,3,4,5,6,1 这时需要插入的数 1( 最小), 这样的过程是:
2,3,4,5,6,6
2,3,4,5,5,6
2,3,4,4,5,6
2,3,3,4,5,6
2,2,3,4,5,6
1,2,3,4,5,6
结论:当 需要插入的数是较小的数时, 后移的次数明显增多,对 效率有影响.

希尔排序是希尔(Donald Shell)于 1959 年提出的一种排序算法。希尔排序也是一种 插入排序,它是简单插入

排序经过改进之后的一个 更高效的版本,也称为 缩小增量排序。

算法思想与图解

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含
的关键词越来越多, 当增量减至 1 时,整个文件恰被分成一组,算法便终止

代码实现

有一群小牛, 考试成绩分别是 8,9,1,7,2,3,5,4,6,0 请从小到大排序. 请分别使用

  1. 希尔排序时, 对有序序列在插入时采用 交换法, 并测试排序速度.
  2. 希尔排序时, 对有序序列在插入时采用 移动法, 并测试排序速度

注: main方法里注释掉的代码是用来测试该算法所用时间的

public class ShellSort 
    public static void main(String[] args) 
        int[] arr = 8,9,1,7,2,3,5,4,6,0;
        System.out.println("排序前:");
        System.out.println(Arrays.toString(arr));
//        int[] arrTest = new int[80000];
//        for (int i = 0; i < arrTest.length; i++) 
//            arrTest[i] = (int)(Math.random()*80000); //生成一个【0,80000】的数
//        

//        Date date1 = new Date();
//        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM--dd HH:mm:ss");
//        String date1Str = simpleDateFormat.format(date1);
//        System.out.println("排序前的时间是="+date1Str);

//        shellSort(arrTest); //测试交换式希尔排序的时间
//        shellSort(arr); // 交换式的希尔排序
//        shellSort2(arrTest); //测试移动式希尔排序的时间
        shellSort2(arr); //移位式的希尔排序

        System.out.println("排序后:");
        System.out.println(Arrays.toString(arr));

//        Date date2 = new Date();
//        SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM--dd HH:mm:ss");
//        String date2Str = simpleDateFormat2.format(date2);
//        System.out.println("排序后的时间是="+date2Str);

    

    //交换法
    // 希尔排序时, 对有序序列在插入时采用交换法,
    // 思路(算法) ===> 代码
    public static void shellSort(int[] arr)

        int temp = 0;
        int count = 0;
        //根据逐步分析,使用循环处理
        for (int gap = arr.length / 2; gap > 0 ; gap /= 2) 
            for (int i = gap; i < arr.length; i++) 
                // 遍历各组中所有的元素(共 gap 组,每组有  个元素), 步长 gap
                for (int j = i - gap; j >= 0; j -= gap) 
                    // 如果当前元素大于加上步长后的那个元素,说明交换
                    /*
                    注: 下面这个if语句里一定不能把 j+gap 写成 i
                      因为第三层for循环里 是为了把当前一组的元素 的大小顺序给排好
                        当 i 的值小的时候,能比较的元素个数也少, 当i逐渐加到最大时, 各个组(注:是不同的组)的顺序会排好

                        举例: 当gap = 2(即第二次希尔排序)时,
                          i一开始为2 , 所以只能arr[0] 和 arr[2]比较
                             接着为3 ,       arr[1]    arr[3]                (1,3为一组)
                                 4          arr[2]和arr[4] 、 arr[0]和arr[2] (0,2,4为一组)
                                 (注: 这时,0,2,4之间的顺序是排好了的,1、3也是)
                                 到了最后一个元素时,各个组内部就都拍好了序
                                 。。。。。。。。。
                     */
                    if (arr[j] > arr[j+gap])
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;
                    
                
            
            //System.out.println("希尔排序第"+(++count)+"一轮后="+ Arrays.toString(arr));
        

        //使用逐步推导的方式编写
//        int temp = 0;
//        //希尔排序的第一轮,是将10个数据分成了5组 (10/2)
//        for (int i = 5; i < arr.length; i++) 
//            // 遍历各组中所有的元素(共 5 组,每组有 2 个元素), 步长 5
//            for (int j = i - 5; j >= 0; j -= 5) 
//                // 如果当前元素大于加上步长后的那个元素,说明交换
//                if (arr[j] > arr[j+5])
//                    temp = arr[j];
//                    arr[j] = arr[j+5];
//                    arr[j+5] = temp;
//                
//            
//        
//        System.out.println("希尔排序第一轮后="+ Arrays.toString(arr));
//
//        //希尔排序的第二轮,是将10个数据分成了5/2 = 2组
//        for (int i = 2; i < arr.length; i++) 
//            // 遍历各组中所有的元素(共 2 组,每组有 5 个元素), 步长 2
//            for (int j = i - 2; j >= 0; j -= 2) 
//                // 如果当前元素大于加上步长后的那个元素,说明交换
//                if (arr[j] > arr[j+2])
//                    temp = arr[j];
//                    arr[j] = arr[j+2];
//                    arr[j+2] = temp;
//                
//            
//        
//        System.out.println("希尔排序第二轮后="+ Arrays.toString(arr));
//
//        //希尔排序的第三轮,是将10个数据分成了2/2 = 1组
//        for (int i = 1; i < arr.length; i++) 
//            // 遍历各组中所有的元素(共 1 组,每组有 10 个元素), 步长 1
//            for (int j = i - 1; j >= 0; j -= 1) 
//                // 如果当前元素大于加上步长后的那个元素,说明交换
//                if (arr[j] > arr[j+1])
//                    temp = arr[j];
//                    arr[j] = arr[j+1];
//                    arr[j+1] = temp;
//                
//            
//        
//        System.out.println("希尔排序第三轮后="+ Arrays.toString(arr));
    

    //对交换式的希尔排序进行优化 -> 移位法
    public static void shellSort2(int[] arr)

        //增量gap, 并逐步的缩小增量
        for (int gap = arr.length / 2; gap > 0 ; gap /= 2) 
            // 从第 gap 个元素, 逐个对其所在的组进行直接插入排序
            for (int i = gap; i < arr.length; i++) 
                int j = i; //存放要插入元素的下标, 最终表示最后要插入位置的下标
                int temp = arr[j]; //存放要插入元素的值
                //跟插入排序算法类似,要找到元素最终插入的位置 (但要注意 步长)
                while (j - gap >= 0 &&  temp < arr[j-gap])
                    //移动
                    arr[j] = arr[j-gap];
                    j -= gap;
                
                //当退出while循环时,说明已经给temp找到了插入的位置
                arr[j] = temp;
            
        
    

运行结果

排序前:
[8, 9, 1, 7, 2, 3, 5, 4, 6, 0]
排序后:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

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

数据结构与算法笔记—— 希尔排序

算法笔记系列:希尔排序

python 学习笔记 -- 数据结构与算法 希尔排序 Shell Sort

希尔排序笔记

Java学习笔记——排序算法之希尔排序(Shell Sort)

经典排序算法学习笔记四——希尔排序