希尔排序学习笔记

最近在学习希尔排序,记录一下学习的笔记

/**
 * 希尔排序
 * 算法步骤:
 * 1. 选择一个递增序列(这里使用的递增序列为 1/2 * (3^k-1) -> 1,4,13,40,121,...)
 * 2. 按递增序列K,对序列进行K趟排序
 * 3. 每趟排序,根据对应的增量ti,将待间隔为ti的元素构成子数组。
 * 在子数组中将每个元素交换到比它大的元素之前去,最终子数组内均有序
 * 4. 按递增序列递减增量ti,重复2.3. 当增量为1时,整个数组有序
 *
 */
function shellSort(arr) {
  arr = arr.slice(0);
  var len = arr.length;
  var gap = 1;
  var temp = null;
  while (gap < Math.floor(len / 3)) {
    gap = 3 * gap + 1;
  }
  while (gap >= 1) {
    // 间隔为gap的元素构成子数组,确保子数组是有序的
    for (var i = gap; i < len; i++) {
      /*
       * j >= gap && arr[j] < arr[j - gap] 关于这句话我理解了好久
       * 为什么用这个作为循环呢?
       * 它的意思是:
       * 首先,数组以及变成多个间隔为gap的子数组了。
       * 然后从元素arr[gap]开始与前面间隔gap的元素arr[0]比较,
       * 如果arr[gap]<arr[0]就要交换
       * 进行完这一过程,arr[gap]肯定是比arr[0]大了,
       * 而且现在arr[gap]前的数组只有arr[0],所以开始比较arr[gap+1];
       * 一直到arr[2*gap]之前,arr[j]都最多只需要交换一次(与arr[j-gap])就可以了
       * 到了arr[2*gap],
       *    a/ 这时如果arr[2*gap] 大于 arr[gap],
       *  而在前面以及确保过arr[gap]和arr[0]是有序的了,
       *  因此arr[2*gap]所在的子数组在它及前面元素已经是有序的了,
       *  进而可以结束循环,进行下一个元素arr[2gap + 1];
       *    b/ 如果arr[2*gap] 小于 arr[gap]
       *  这时arr[2*gap]之前的子数组是有序的,
       *  因此至少是说arr[2*gap]小于前面的一个最大值,
       *  为了保证arr[2gap]及之前的有序,需要进行交换
       *  首先arr[2gap]的值A 与间隔gap的arr[gap]的值B交换,
       *  此时值A在arr[gap]的位置上了,
       *  这时显然还需要继续比较arr[gap]与arr[0]才能确保,
       *  arr[2gap]、arr[gap]、arr[0]三者是有序的
       *  因此
       *  循环会判断j从2gap变成gap(值A所在位置索引)后前面还有没有元素(j >= gap)
       *  这时是有的(arr[0])于是循环会继续判断arr[j]是不是比前一个元素大
       *  这里其实是和前面元素的最大值做比较,因此只要大于等于就可以直接结束循环了
       *  小于就进行交换,至此arr[2gap]所在子数组,在它及它之前的元素均已有序,
       *  继续下面的循环,直到在间隔为gap的所有子数组有序为止
       */
      for (var j = i; j >= gap && arr[j] < arr[j - gap]; j -= gap) {
        temp = arr[j];
        arr[j] = arr[j - gap];
        arr[j - gap] = temp;
      }
    }

    // 按照递增序列递减间隔
    gap = Math.floor(gap / 3);
  }
  return arr;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值