[路飞]_快速排序(QuickSort)

354 阅读1分钟

参考 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

算法思想

快速排序的精髓就是分治,然后在冒泡排序的基础上递归分治。

  1. 从数组中挑出一个基准值
  2. 根据基准值重排数组,将小于基准值的元素放在前面,将大于基准值的元素放在后面,然后将基准值放在中间,这个过程成为分区(partition)
  3. 分别递归左右分区进行排列

动画演示

quickSort.gif

代码实现简单版(JS)

const arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]

/**
 * @param {Number[]} arr
 * @param {Number} l
 * @param {Number} r
 */
function quickSort(arr, l, r) {
  if (l >= r) return
  let x = l, //左指针
    y = r, //右指针
    base = arr[l] //取第一个元素为基准值
  // partition
  while (x < y) {
    while (x < y && arr[y] >= base) { //从数组右边往前找到第一个小于基准值的元素
      y--
    }
    if (x < y) { //把小于基准值的元素放到基准值左边,同时左指针向后一步
      arr[x++] = arr[y]
    }
    while (x < y && arr[x] <= base) { //从数组左边往后找到第一个大于基准值的元素
      x++
    }
    if (x < y) { //把大于基准值的元素放到基准值右边,同时右指针向前一步
      arr[y--] = arr[x]
    }
  }
  arr[x] = base //此时所有小于基准值的元素都在左边,大于基准值的元素都在右边
  // 到这里分别递归左半边和右半边
  quickSort(arr, l, x - 1)
  quickSort(arr, x + 1, r)
  return
}

quickSort(arr, 0, arr.length - 1)

console.log(arr) //[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

单边递归

/**
 * @param {Number[]} arr
 * @param {Number} l
 * @param {Number} r
 */
function quickSort(arr, l, r) {
  while (l < r) {
    let x = l,
      y = r,
      base = arr[l]
    while(x < y) {
      while (x < y && arr[y] >= base) {
        y--
      }
      if (x < y) {
        arr[x++] = arr[y]
      }
      while (x < y && arr[x] <= base) {
        x++
      }
      if (x < y) {
        arr[y--] = arr[x]
      }
    }
    arr[x] = base
    quickSort(arr, x + 1, r)
    r = x - 1 //减少一次递归
  }
}