快速排序算法详解

151 阅读3分钟

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战

介绍

快速排序是一个经典的排序算法,在待排序的记录中任取一个记录(通常取第一个)作为枢纽,设其关键字为pivotkey,经过一趟排序后,把记录值小于pivotkey的交换到前面,大的交换到后面,将待排序记录分成两个表,分别对两个表重复上述过程,直到每一子表只有一个记录。

特点

快速排序是对冒泡排序的一种改进,时间复杂度为,平均情况是O(nlogn),最坏情况是O(n^2)。最坏情况也就是当排序已经成为基本有序状态时。他的特点如下:

  1. 不稳定的排序,也就是如果相同的两个数字,无法保证其相对位置不发生变化。
  2. 排序过程需要定位表的下界和上界,所以适用于顺序结构,很难用于链式结构
  3. 当n较大时,在平均情况下快速排序是所有内部排序方法中速度最快的一种,所以其适合初始记录无序,n较大情况

步骤

现在有一个数组[49,38,65,97,76,13,27,49],我们需要通过快速排序算法对其进行排序。下面我们就来解析第一趟的运行逻辑。

第一步:设置第一个数 49 位枢纽,令 i = 0, j= n-1,从数组末尾开始遍历令j=j-1,直到找出比枢纽值小的数,找到27,因为是右往左第一个比枢纽值小的数,然后把它赋值给 i的位置。这时候的数组

/*
    枢纽值:49
    (27), 38, 65, 97, 76, 13, 27, 49
位置  i                        j
*/

第二步:然后再从左边i的位置开始遍历令i=i+1,直到找出比枢纽值第一个大的数,为 65,然后把它赋值到 j的位置。这时候的数组

/*
    枢纽值:49
     27, 38, 65, 97, 76, 13, (65), 49
位置          i                j
*/

第三步:重复上述两步骤,直到 i === j 为止,这时候再把枢纽值赋值给 j,到此,就完成了第一趟排序,这个位置的左边都小于枢纽值,右边都大于枢纽值。这时候的数组就完成了第一趟排序,

/*
    枢纽值:49
     27  38  13  (49) 76  97  65  49
位置              i==j              
*/

这时候数组被分成了两部分,在分别对这两部分重复上面三个步骤,直到排序完成。

这个就是快速排序的详细步骤。

代码

JavaScript版

const quickSort = (array) => {
  const sort = (arr, left = 0, right = arr.length - 1) => {
    if (left >= right) {//如果左边的索引大于等于右边的索引说明整理完毕
      return
    }
    let i = left
    let j = right
    const pivotkey = arr[i] // 取无序数组最后一个数为基准值
    while (i < j) { //把所有比基准值小的数放在左边大的数放在右边
      while (i < j && arr[j] >= pivotkey) { //找到一个比基准值小的数交换
        j--
      }
      arr[i] = arr[j] // 将较小的值放在左边
      while (j > i && arr[i] <= pivotkey) { //找到一个比基准值大的数交换
        i++
      }
      arr[j] = arr[i] // 将较大的值放在右边
    }
    arr[i] = pivotkey // 将基准值放至中央位置完成一次循环(这时候 j 等于 i )
    sort(arr, left, j-1) // 将左边的无序数组重复上面的操作
    sort(arr, j+1, right) // 将右边的无序数组重复上面的操作
  }
  sort(array)
  return array
}

总结

与直接插入算法比,一开始还是不太容易的,主要要搞清 i 和 j 的位置关系。