zoukankan      html  css  js  c++  java
  • 希尔排序--学习笔记

      希尔排序(Shellsort)由Donald Shell提出,对直接插入排序进行了改进。由于其算法特征,又叫做"缩减增量排序"。

      希尔排序使用一个增量序列(h1, h2, h3, ..., hk),只要h1 = 1,任何增量序列都是可行的,增量序列不唯一,但有的增量序列比另一些增量序列要好。希尔排序的一个重要性质是,一个hk排序的文件保持它的hk排序性。其中,一趟hk排序的作用就是对hk个独立的子数组分别执行一次插入排序。(摘自《算法和数据结构》)

    算法分析

      概念总是显得有点深奥,从例子去分析:

      假设我们有一个数组:

    var s = [21, 3, 36, 81, 12, 7, 23, 48, 62, 95, 44, 73];
    

      选择一个增量序列h1=1,h2=2,h3=4。

      1.执行一次4排序:将原数组分为四个独立的子数组,对四个子数组进行插入排序,

      ①将黄色数组排序,其他不变

      ②同理

      ③同理

      ④同理

      2.继续执行2排序:将4排序后的数组分为两个独立的子数组,分别进行插入排序,

      ①将黄色部分排序

      ②同理

      3.最后进行1排序:将整个数组进行一次插入排序,

      此时,数组已经排序。

      由此看来,希尔排序就是若干个插入排序,只不过一个hk排序改变了不止一个数的位置(因为一个hk排序包含了hk个插入排序),而插入排序一趟只能将数据移动以为。1排序就是一个插入排序。

    代码实现

     1 var s = [21, 3, 36, 81, 12, 7, 23, 48, 62, 95, 44, 73];
     2 var shellSort = function(array) {
     3     var temp;
     4     var gap = Math.floor(array.length/2);
     5     for(gap;  gap > 0; gap = Math.floor(gap/2)) {
     6         for(var i = gap; i < array.length; i++) {
     7             temp = array[i];
     8             for(var j = i; j >= gap && temp-array[j-gap] < 0; j -= gap) {
     9                 array[j] = array[j - gap];
    10             }
    11             array[j] = temp;
    12         }
    13     }
    14     return array;
    15 };
    16 console.log(shellSort(s));
    17 //=>[ 3, 7, 12, 21, 23, 36, 44, 48, 62, 73, 81, 95 ]

      代码参考自《算法和数据结构》。

      第5行for为增量序列的选取,采用shell建议的hk=N/2(向下取整);

      第6~12行为插入排序的代码,很巧妙,将第5行的for去掉,将gap值改为1,就变成了一个纯粹的插入排序:

     1 var s = [21, 3, 36, 81, 12, 7, 23, 48, 62, 95, 44, 73];
     2 var shellSort = function(array) {
     3     var temp;
     4     for(var i = 1; i < array.length; i++) {
     5         temp = array[i];
     6         for(var j = i; j >= 1 && temp - array[j - 1] < 0; j -= 1) {
     7             array[j] = array[j - 1];
     8         }
     9         array[j] = temp;
    10     }
    11     return array;
    12 };
    13 console.log(shellSort(s));
    14 //=>[ 3, 7, 12, 21, 23, 36, 44, 48, 62, 73, 81, 95 ]

      这也说明了1排序就是一个插入排序,也是hk序列必须包含hk=1的原因。

      另外,为了在学习过程中更好地观察每个hk排序的结果,我把代码修改如下,其中shellSort还接受一个hk

     1 var s = [21, 3, 36, 81, 12, 7, 23, 48, 62, 95, 44, 73];
     2 var shellSort = function(array, gap) {
     3     var temp;
     4     for(var i = gap; i < array.length; i++) {
     5         temp = array[i];
     6         for(var j = i; j >= gap && temp - array[j - gap] < 0; j -= gap) {
     7             array[j] = array[j - gap];
     8         }
     9         array[j] = temp;
    10     }
    11     return array;
    12 };
    13 var h4 = shellSort(s, 4);
    14 console.log(h4);
    15 var h2 = shellSort(h4, 2);
    16 console.log(h2);
    17 var h1 = shellSort(h2, 1);
    18 console.log(h1);
    19 //=>[ 12, 3, 23, 48, 21, 7, 36, 73, 62, 95, 44, 81 ]  //4排序后
    20     [ 12, 3, 21, 7, 23, 48, 36, 73, 44, 81, 62, 95 ]  //2排序后
    21     [ 3, 7, 12, 21, 23, 36, 44, 48, 62, 73, 81, 95 ]  //1排序后

     

    总结

      1.希尔排序是通过一个增量序列来将数组元素调整到一个"比较有序"的状态,最后对整个最数组进行一次插入排序(1排序)。有可能在1排序前数组就以排序,这样1排序只需要线性时间;也有可能前面的hk排序并没有改变数组的序列,从而1排序时花费很多的时间。

      2.增量序列的选择不是唯一的,存在更具排序效率的增量序列。  

    ---------------------------------------------------------------------------------

    本文为个人学习随笔,仅供个人学习,如有雷同,敬请原谅。

  • 相关阅读:
    小米手机miui8.5连接电脑
    js数组map方法
    wxui入门
    动画函数封装
    系列属性(offset、scroll、client)
    定时器( setInterval和 setTimeout)
    BOM(浏览器对象模型)
    事件(绑定、解绑、冒泡)
    元素(element)创建
    节点(node)操作
  • 原文地址:https://www.cnblogs.com/alicell/p/9085138.html
Copyright © 2011-2022 走看看