排序算法之——希尔排序

142 阅读2分钟

背景

由于 插入排序, 只会交换相邻元素, 因此只能一点点的从数组的一端移动到另一端, 如意 最小的元素 正好在 数组的末端, 那么 就得移动 N1N-1 次 , 因此 希尔排序在插入排序的基础上进行了改进, 交换不相邻的元素进行对数组进行局部排序, 并最终进行数组排序

希尔排序

希尔排序: 将全部元素分为几个部分来进行排序, 这样可以使的一个元素可以一次性的移动一大步, 然后不断的通过减小步长进行排序, 到最后进行 普通的插入排序, 此时 基本上 整个元素 近乎已经 排好序, 这样插入排序 就会更快一点

数据结构: 数组

时间复杂度

根据步长的序列不同而不同;

最好的时间复杂度: O(n)O(n)

最坏的时间复杂度: O(nlog2n)O(nlog^2n)

示例

现有一个无序数组 const arr = [823,427,26,822,81,931,585,424]

  • 第一步: 设置步长h为 数组的一半, h = arr.length / 2 = 4 得到一个类似下面的样子
8234272682281931585424\begin{matrix} 823&427&26&822 \\ 81&931&585&424 \\ \end{matrix}

image.png

  • 第二步: 对列进行排序得到, 得到一个 [81, 427, 26, 424, 823, 931, 585, 822]

    8142726424823931585822 \begin{matrix} 81&427&26&424 \\ 823&931&585&822 \\ \end{matrix}

  • 第三步: 将步长h, 继续缩小 一半; h = h / 2 = 2, 可以得到看似以下结构

    8142726424823931585822\begin{matrix} 81&427\\ 26&424\\ 823&931\\ 585&822\\ \end{matrix}

  • 第四步: 对列进行排序得到[26, 424, 81, 427, 585, 822, 823, 931]

    2642481427585822823931 \begin{matrix} 26&424\\ 81&427\\ 585&822\\ 823&931\\ \end{matrix}

  • 第五步: 将步长继续缩小一半, 此时 为 1, 那么就开始了插入排序, [26, 81, 424, 427, 585, 822, 823, 931]

代码实现(Typescript)

/**
 * 生成指定的随机数
 * @param count {number}
 * @param min {number} 
 * @param max {number}
 * @returns Array<number>
 */
function getRandomInteger(count: number = 1, min: number = 0, max: number = 1000): Array<number> {
  const res: Array<number> = []
  for (let i = 0; i < count; i ++ ){
    const random = Math.floor(Math.random() * (max - min) + min)
    res.push(random)
  }
  return res
}
/**
 * 希尔排序
 * @param arr 
 * @returns 
 */
function shellSort (arr: Array<number>): Array<number> {
  if (arr.length < 2) return arr
  for (let step = arr.length >> 1; step > 0; step >>= 1) {
    for (let i = step; i < arr.length; i++) {
      const curValue:number = arr[i]
      let j: number = i - step
      for (; j >= 0 && arr[j] > curValue; j -= step) {
        arr[j + step] = arr[j]
      }
      arr[j + step] = curValue
    }
  }
  return arr
}
const randoms: Array<number> = getRandomInteger(10)
console.log("排序前:"  + randoms) // 排序前:934,173,734,595,779,278,554,440,562,206
console.log("排序后:" + shellSort(randoms)) // 排序后:173,206,278,440,554,562,595,734,779,934