排序算法-交换排序-快速排序-方式二

240 阅读3分钟

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

快速排序

介绍

快速排序 通过这个名字,我们就知道他是排序算法中最快的 排序算法。

上一篇 已经介绍了一种 快速排序 的方法。

现在 介绍 快速排序 的第二种方式。第二种方法 其实也很好理解,其中用到了数据结构中的 双指针算法 中的 对撞指针,可以先看下对应的 数据结构-双指针算法 这篇文章的讲解

  • 快速排序 方式二 的原理就是:

    将给定一组数据,首先产生一个对撞指针,leftright 下标 分别对应,数据的 最左侧 和 最右侧。

    然后默认选取最左侧数据下标为 基准点 ,所对应的值(基准点的值)保存起来,记作 temp

    然后从剩余的数据中,从 right 下标 所对应的值开始进行比对,如果值大于该 基准点的值 ,则 right--,若小于则 从 left 下标重新开始。

    判断 left 所对应的值 是否小于该基准点的值,若小于,则 left++,若不小于,则将 left 的下标 和 right 的下标 的值进行交换。

    循环进行,直到判断 left >= right,结束循环,并将 temp 值与 两个指针相遇 下标所对应的值 交换。

步骤详解

image.png

  • 上图是给定的数据 const arr = [15,5,25,20,30,10]

  • 初始化 begin = 0end = arr.length-1

  • 获取 基准点基准点的值

        // 基准点 
        let left = begin
        
        // 基准点的值
        const temp = arr[begin]
    

    可得上图的 基准点 为下图紫色部分:0

    基准点的值 为:15

    image.png

  • 从右开始先与 基准点的值 比较

        let right = end
        
        while (left < right && arr[right] >= temp) right--
    

    由上面代码可知第一次的 right 为 5,所对应的值为 10

    image.png

  • 再从左开始先与 基准点的值 比较

        while (left < right && arr[left] <= temp) left++
    

    由上面代码可知第一次的 left 为 2,所对应的值为 25

    image.png

  • 进行交换

        if (left !== right) {
          // 交换 左右指针 所停位置的数
          exchangeFunc(arr, left, right)
        }
    

    如果 left 小于 right,则交换两个指针 所对应的值。

    image.png

  • 重复进行

    由于 left < right,所以需要继续上述重复进行上述步骤后,直到 left >= right 才能结束第一次循环。

    image.png

  • 交换第一次结果

    循环结束后,进行 temp 和 两指针相交 位置的值进行交换。得到的结果为

    arr = [10,5,15,20,30,25]

    image.png

  • 递归 左右数据

    由上图可知,此时数据被分为 左数组 和 右数据。我们需要递归操作得到最终的结果。

      quickSort(arr, begin, left - 1)
      quickSort(arr, left + 1, end)
    

比较

为什么要讲解 快速排序方式二 呢,第一种方式确实 是很好理解,但是不是 快速排序 的真正速度。

所以这里创建一份 百万条 随机数据:

  const arr = []

  for (let i = 0; i < 10000000; i++) {
    const num = Math.floor(Math.random() * 10000000)
    arr.push(num)
  }

然后对两种方式 分别进行耗时比较:

  • 第一种
  console.time('耗时')
  quickSort1(array2)
  console.timeEnd('耗时')
  • 第二种
  console.time('耗时')
  const a = quickSort(arr, 0, arr.length - 1)
  console.timeEnd('耗时')

耗时对比图

image.png

可以看到,耗时相比,几乎是 7 倍的差距,而且数据越多,差距越大。

完整代码

    const quickSort = (arr, begin, end) => {
      // 左指针和右指针相等时候,说明只有一个值
      if (begin >= end) return

      let left = begin
      let right = end
      const temp = arr[begin] // 基准点,这里取数组第一个数作为 基准点 的值

      // 左右指针相遇的时候退出扫描循环
      while (left < right) {

        // 右指针从 右向左扫描
        while (left < right && arr[right] >= temp) right--

        // 左指针从 左向右扫描
        while (left < right && arr[left] <= temp) left++

        if (left !== right) {
          // 交换 左右指针 所停位置的数
          exchangeFunc(arr, left, right)
        }
      }
      // 最后交换 基准数 与 两个指针 相遇位置 的 数
      exchangeFunc(arr, begin, left)

      // 递归处理左右数组
      quickSort(arr, begin, left - 1)
      quickSort(arr, left + 1, end)
      return arr
    }

    /**
     * 进行交换
     * @param {array} arr
     * @param {number} A
     * @param {number} B
     */
    const exchangeFunc = (arr, A, B) => {
      const temp = arr[B]
      arr[B] = arr[A]
      arr[A] = temp
    }

总结

快速排序 方式二 与 方式一 相比的优点:

  • 不用创建新的数组,开辟新内存。

  • 在百万条数据下,速度极快。