希尔排序

希尔排序

概述

希尔排序是插入排序的改进版,也称缩小增量排序。其核心思想是将原始数组按增量分成多个子序列,对每组进行插入排序,随后逐步缩小增量直至为1,最终完成整体排序。

常见的增量序列间隔选择方式

  1. Shell原始序列 :1 2 ... <math xmlns="http://www.w3.org/1998/Math/MathML"> n / 4 n/4 </math>n/4 <math xmlns="http://www.w3.org/1998/Math/MathML"> n / 2 n/2 </math>n/2 (n为原始数组长度)

  2. Hibbard序列 :1 3 7 ... <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 k − 1 2^k-1 </math>2k−1

  3. Knuth序列 :1 4 13 ... <math xmlns="http://www.w3.org/1998/Math/MathML"> ( 3 k − 1 ) / 2 (3^k-1)/2 </math>(3k−1)/2

    最佳增量序列的的选择仍然是一个研究方向。

JavaScript实现

Shell序列

javascript 复制代码
function shellSort(list) {
    let n = list.length;
    let gap = n >> 1;
    while (gap) {
        // 分别处理以i开头,间隔gap的子序列
        for (let i = 0; i < gap; i++) {
            for (let j = i + gap; j < n; j += gap) {
                let k = j - gap;
                while (k >= 0 && list[k] > list[k + gap]) {
                    swap(list, k, k + gap);
                    k -= gap;
                }
            }
        }
        // 缩小gap
        gap = gap >> 1;
    }
    return list
}


for (let i = 0; i < 100; i++) {
    let list = generateList();
    console.log('origin list', list);
    let a = sort(clone(list)), b = shellSort(clone(list));
    console.log('sorte', a);
    console.log('shell', b);
    for (let j = 0; j < list.length; j++) if (a[j] !== b[j]) console.log('error');
    console.log('success')
}


// ---------------help----------------------

function clone(list) {
    return list.slice(0);
}

function swap(list, i, j) {
    var temp = list[i];
    list[i] = list[j];
    list[j] = temp;
}

function generateList() {
    let length = 10 + Math.ceil(Math.random() * 10);
    let list = [];
    while (length) {
        list.push(Math.ceil(Math.random() * 100));
        length--;
    }
    return list;
}

function sort(list) {
    list.sort((a, b) => a - b);
    return list;
}

Hibbard序列

javascript 复制代码
function shellSortByHibbard(list) {
    let n = list.length, K = Math.floor(Math.log2(n + 1));
    console.log('长度', n, 'K=', K);
    while (K) {
        let gap = Math.pow(2, K) - 1;
        // 分别处理以i开头,间隔gap的子序列
        for (let i = 0; i < gap; i++) {
            for (let j = i + gap; j < n; j += gap) {
                let k = j - gap;
                while (k >= 0 && list[k] > list[k + gap]) {
                    swap(list, k, k + gap);
                    k -= gap;
                }
            }
        }

        K--;
    }
    return list;
}

Knuth序列

javascript 复制代码
function shellSortByKnuth(list) {
    let n = list.length, K = Math.floor(Math.log(2 * n + 1) / Math.log(3));
    console.log('长度', n, 'K=', K);
    while (K) {
        let gap = (Math.pow(3, K) - 1) >> 1;
        // 分别处理以i开头,间隔gap的子序列
        for (let i = 0; i < gap; i++) {
            for (let j = i + gap; j < n; j += gap) {
                let k = j - gap;
                while (k >= 0 && list[k] > list[k + gap]) {
                    swap(list, k, k + gap);
                    k -= gap;
                }
            }
        }

        K--;
    }
    return list;
}
相关推荐
一斤代码2 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子2 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年2 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子3 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina3 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路4 小时前
React--Fiber 架构
前端·react.js·架构
coderlin_4 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
伍哥的传说4 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409194 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app
我在北京coding4 小时前
element el-table渲染二维对象数组
前端·javascript·vue.js