阅读 34

插入排序优化之希尔排序

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

希尔排序

希尔排序的本质是插入排序,如果是一个大规模乱序数组,由于插入排序只是交换相邻元素,所以插入排序会比较慢。而希尔排序的思想就是,先使数组中任意间隔h个元素排序,然后再全局排序。时间复杂度可以由原来的O(n²),优化为O()

h的取值逻辑

举个例子,针对一个大规模乱序数组,可以先取值22间隔排序,即每隔22个元素,取一个元素,然后把这些元素进行排序、然后再取每10间隔元素,再排序、以此类推然后是4间隔排序、最后间隔1全局排序,所以h的取值是1、4、10、22。
维基百科有提供一张公式表,用于h计算

image.png

比较常用的公式为红框这个,其中k为自然数1,2,3,4... N为数组长度

希尔排序的举例分析

假设有一数组,长度为16 image.png 根据公式
image.png

  • k依次取值 1,2,3,4,5...自然数,满足h < N/3时取值为[1, 4]
  • 此时,先间隔4排序:此时第一次取index=4元素51与index=0元素34比较,51 > 34,所以不做任何操作;然后取index=5idnex=1比较,34 > 22,同样不做操作,以此类推。假设当遍历到最后一个元素index=15时,会依次对index = 11,7,3对应的元素进行排序

代码

    // h取值计算
    const geth = function(N) { // N 为数组长度
        let hList = [] // h 取值数组
        let k = 1
        let h = 1
        while(h <= N/3) {
            h = (Math.pow(3, k) - 1) / 2
            if ( h > N/3) break
            hList.push(h) // 1, 4
            k++
        }
        return hList
    }
    // 希尔排序
    const shellsort = function(arr) {
        let hList = geth(arr.length) // 获取h的取值
        for(let k = hList.length - 1; k >= 0; k--) { // h取值倒序遍历
            let h = hList[k]
            // 将数组变为每间隔h有序
            for(let i = h; i < arr.length; i++) {
                for(let j = i; j >= h; j = j - h) {
                    if (arr[j] < arr[j - h]) {
                        let temp = arr[j]
                        arr[j] = arr[j - h]
                        arr[j - h] = temp
                    } else {
                        break
                    }
                }
            }
        }
    }
复制代码

相关推荐

彻底搞懂插入排序、选择排序、冒泡排序及优化

文章分类
前端