快速排序

快速排序的思路是,先选择任意元素为轴,将比轴小的元素都放在其左边,比轴大的元素都放在其右边,这样轴的位置一定是正确的。之后通过递归,对轴左右两边的元素都进行快速排序。最终实现整个数组有序。

那么第一个问题来了,怎么选择轴呢?这里b站的coderwhy老师给出一种方案:让数组首尾中三处元素当中的中位数作为初始轴,最大值放在末尾,最小值放在开头。最后将初始轴和数组倒数第二位的元素交换,将轴返回。

代码如下:

      ArrayList.prototype.median = function (left, right) {
        //  以首尾中三处元素的中位数作为轴的初值
        let center = Math.floor((left + right) / 2)
        let x = this.array[left],
            y = this.array[center],
            z = this.array[right]       
        let arr = [x, y, z]
        arr.sort( (a, b) => {
          return a - b
        })
        this.array[left] = arr[0]
        this.array[center] = arr[1]
        this.array[right] = arr[2]
        //  将轴放在倒数第二个元素上
        this.swap(right - 1, center)
        return this.array[right - 1]
      } 

我们已经得到了轴,并且轴位于数组的倒数第二位,倒数第一位的元素已经确认大于轴,所以不用关心。接下来,只需要考虑轴前面的元素即可。

定义两个指针,左指针 i 指向数组开头,右指针指向轴

let i = left,
    j = right - 1

接下来两个代码块写在一个死循环中:

左指针逐个格子向右移动,当遇到大于或等于轴的值时,就停下来。
右指针逐个格子向左移动,当遇到小于或等于轴的值时,就停下来。
简单的说就是把轴左边的大值移到右边,把轴右边的小值移到左边。
while (this.array[++i] < pivot) {}
while (this.array[--j] > pivot) {}
若左指针还在右指针的左边,将两指针所指的值交换位置。否则,退出循环。
if (i < j) {
   this.swap(i, j)
} else {
   break
}     
退出循环时,左指针的位置就是轴元素应该所处的位置:
this.swap(i, right - 1)
递归调用当前方法处理轴左、右两边的元素:
this.quick(left, i - 1)
this.quick(i + 1, right)

接下来需要考虑一些特殊情况,比如轴左边只有一个元素,不需要进行处理;或者轴右边只有两个元素,必要的话交换一下位置即可:

if (left >= right) return
if( right - left == 1){
   if(this.array[left] > this.array[right]){
       this.swap(left, right)
   }
   return
}

完整代码如下:

ArrayList.prototype.quickSort = function () {
        let length = this.array.length
        this.quick(0, length - 1)
}
ArrayList.prototype.quick = function (left, right) {
        if (left >= right) return
        if( right - left == 1){
          if(this.array[left] > this.array[right]){
            this.swap(left, right)
          }
          return
        }
        let pivot = this.median(left, right)
        let i = left,
            j = right - 1
        while (true) {
          while (this.array[++i] < pivot) {}
          while (this.array[--j] > pivot) {}
          if (i < j) {
            this.swap(i, j)
          } else {
            break
          }
        }
        this.swap(i, right - 1)
        this.quick(left, i - 1)
        this.quick(i + 1, right)
}

 

posted on 2021-06-22 16:41  springxxxx  阅读(51)  评论(0编辑  收藏  举报