• Java与算法之(10)


    希尔排序是插入排序的一种,是直接插入排序的改进版本。

    对于上节介绍的直接插入排序法,如果数据原来就已经按要求的顺序排列,则在排序过程中不需要进行数据移动操作,即可得到有序数列。但是,如果最初的数据是按倒序排列的,则在进行插入排序时每次的比较都需要向后移动数据,这样,将导致算法的效率很低。

    希尔排序的思想是把数列划分为若干个较小的数列,对每组数列使用直接插入排序算法排序,随着增量逐渐减少,每组包含的数字越来越多,当增量减至1时,整个数列恰被分成一组,最后再使用一次直接插入排序对整个数列进行排序。

    例如有4, 3, 6, 2, 7, 1, 5, 8八个数字,第一次分成四组,即8/2组。如下图,相同颜色的数字为一组,下标为x的数字和下标为x+4的数字为一组。

    对这四个数组分别做直接插入排序,即两两比较,如果大的在前则交换位置,得到:

    然后缩小组数,4/2=2,缩小为两组。如下图:

    对这两个数组分别做直接插入排序,得到:

    再次缩小组数,2/2=1,缩小为一组,那么所有数字都。如下图:

    最后,对4, 1, 5, 2, 6, 3, 7, 8这个数列执行一次直接插入排序。

    总结上面的规律,可以得出:

    第一次分组数s = n / 2 == 0 ? n / 2 : n / 2 + 1

    取数规则是[x]和[x+n/2]为一组

    当然,这只是比较简单的分组方式,不一定是最优的。来看代码:

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. public class ShellSort {  
    2.     private int[] numbers;  
    3.   
    4.     public ShellSort(int[] numbers) {  
    5.         this.numbers = numbers;  
    6.     }  
    7.   
    8.     /** 
    9.      * 对数组分组并对每个组做直接插入排序, 完成后缩小组的数量, 重复插入排序, 直到缩小到一个组 
    10.      * 第一次分组数: section = n/2 == 0 ? n/2 : n/2+1, 分组规则: 每隔n/2挑一个数, 即[x]和[x+n/2]为一组 
    11.      */  
    12.     public void sort() {  
    13.         int section = this.numbers.length / 2;  
    14.         int j;  
    15.         int temp;  
    16.         while(section >= 1) {  
    17.             for(int i = section; i < this.numbers.length; i++) {  
    18.                 temp = this.numbers[i];  
    19.                 j = i - section;  
    20.                 while(j >= 0 && this.numbers[j] > temp) {  
    21.                     this.numbers[j + section] = this.numbers[j];  
    22.                     j = j - section;  
    23.                 }  
    24.                 this.numbers[j + section] = temp;  
    25.             }  
    26.             section /= 2;  
    27.         }  
    28.         System.out.print("排序后: ");  
    29.         for(int x = 0; x < numbers.length; x++) {  
    30.             System.out.print(numbers[x] + "  ");  
    31.         }  
    32.     }  
    33.   
    34.     public static void main(String[] args) {  
    35.         int[] numbers = new int[] { 4, 3, 6, 2, 7, 1, 5, 8 };  
    36.         System.out.print("排序前: ");  
    37.         for(int x = 0; x < numbers.length; x++) {  
    38.             System.out.print(numbers[x] + "  ");  
    39.         }  
    40.         System.out.println();  
    41.         ShellSort ss = new ShellSort(numbers);  
    42.         ss.sort();  
    43.     }  
    44. }  

    运行:

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. 排序前: 4  3  6  2  7  1  5  8    
    2. 排序后: 1  2  3  4  5  6  7  8    

    希尔排序的时间复杂度,最坏是O(n^2),平均O(n^3/2)。

  • 相关阅读:
    Java包装类
    Java锁机制ReentrantLock
    Java内部类介绍
    JAVA多线程学习六-守护线程
    JAVA多线程学习五:线程范围内共享变量&ThreadLocal
    JAVA多线程学习四
    Maven之阿里云镜像仓库配置
    JAVA多线程学习- 三:volatile关键字
    ansible学习(二)- 清单配置详解
    Java多线程学习(二)
  • 原文地址:https://www.cnblogs.com/sa-dan/p/6837074.html
Copyright © 2020-2023  润新知