Skip to content
On this page

快速排序

快速排序在基本思想上和归并排序是一致的,仍然坚持“分而治之”的原则不动摇。区别在于,快速排序并不会把真的数组分割开来再合并到一个新数组中去,而是直接在原有的数组内部进行排序。

分的原则是什么?先找一个基准值 mid,两个指针: l = 0, r = length - 1 如果 arr[l] < arr[mid] l++ 如果 arr[r] > arr[mid] r-- 如果 l <= r 则意味着基准值左边存在较大元素或右边存在较小元素,交换两个元素确保左右两侧有序

js
function quickSort(arr, left = 0, right = arr.length - 1) {
  // 定义递归边界,若数组只有一个元素,则没有排序必要
  if (arr.length > 1) {
    // lineIndex表示下一次划分左右子数组的索引位
    const lineIndex = partition(arr, left, right)
    // 如果左边子数组的长度不小于1,则递归快排这个子数组
    if (left < lineIndex - 1) {
      // 左子数组以 lineIndex-1 为右边界
      quickSort(arr, left, lineIndex - 1)
    }
    // 如果右边子数组的长度不小于1,则递归快排这个子数组
    if (lineIndex < right) {
      // 右子数组以 lineIndex 为左边界
      quickSort(arr, lineIndex, right)
    }
  }
  return arr
}
// 以基准值为轴心,划分左右子数组的过程
function partition(arr, left, right) {
  // 基准值默认取中间位置的元素
  let pivotValue = arr[Math.floor(left + (right - left) / 2)]
  // 初始化左右指针
  let i = left
  let j = right
  // 当左右指针不越界时,循环执行以下逻辑
  while (i <= j) {
    // 左指针所指元素若小于基准值,则右移左指针
    while (arr[i] < pivotValue) {
      i++
    }
    // 右指针所指元素大于基准值,则左移右指针
    while (arr[j] > pivotValue) {
      j--
    }

    // 若i<=j,则意味着基准值左边存在较大元素或右边存在较小元素,交换两个元素确保左右两侧有序
    if (i <= j) {
      swap(arr, i, j)
      i++
      j--
    }
  }
}

const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]]

这样也行:

js
// 简单说: 找到一个数作为参考,比这个数字大的放在数字左边,比它小的放在右边; 然后分别再对左边和右变的序列做相同的操作:
//(1)选择一个基准元素,将列表分割成两个子序列;
//(2)对列表重新排序,将所有小于基准值的元素放在基准值前面,所有大于基准值的元素放在基准值的后面;
//(3)分别对较小元素的子序列和较大元素的子序列重复步骤1和2
function quickSort(arr) {
  const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]]
  if(arr.length <= 1) return arr
  const mid = Math.floor((arr.length - 1) / 2)
  let i = 0, j = arr.length - 1
  while(i <= j) {
    while(arr[i] < arr[mid]) { // 找到 左侧 比这个中间值大的
      i++
    }
    while(arr[j] > arr[mid]) { // 找到 右侧 比这个中间值小的
      j--
    }
    if(i <= j) {
      swap(arr, i, j) // 交换左右两侧
      i++
      j--
    }
  }
  const left = quickSort(arr.slice(0, i)) // 递归去处理
  const right = quickSort(arr.slice(i))
  return left.concat(right)
}

还可以这样:

js
function quickSort(arr) {
  if(arr.length <= 1) return arr
  const mid = Math.floor(arr.length / 2)
  const left = []
  const right = []
  const midVal = arr.splice(mid, 1)
  for (let i = 0; i < arr.length; i++) {
    if(arr[i] < midVal) {
      left.push(arr[i])
    } else {
      right.push(arr[i])
    }
  }
  return quickSort(left).concat(midVal, quickSort(right))
}