数据结构与算法——排序3(快速排序)

一、🐶 快速排序的原理

  • 分区: 从数组中任意选择一个基准,所有比基准小的元素放到基准前面,比基准大的元素放到基准的后面
  • 递归:递归地对基准前后的子数组进行分区

快排实现方式一代码如下(不考虑空间消耗):

js 复制代码
Array.prototype.quickSort = function () { 
    const rec = (arr) => { 
       // 预防数组是空的或者只有一个元素, 当所有元素都大于等于基准值就会产生空的数组
       if(arr.length === 1 || arr.length === 0) { return arr; }
       const left = [];
       const right = [];
       //以第一个元素作为基准值   
       const mid = arr[0];
       //小于基准值的放左边,大于基准值的放右边
       for(let i = 1; i < arr.length; ++i) { 
           if(arr[i] < mid) { 
               left.push(arr[i]);
           } else { 
               right.push(arr[i]);
           }
       }
        //递归调用,最后放回数组    
       return [...rec(left),mid,...rec(right)];
    };
    const res = rec(this);
    res.forEach((n,i) => { this[i] = n; })
}

const arr = [2,3,4,5,3,1];
arr.quickSort();
console.log(arr);

总结:简明易懂,好理解,好写,适合面试的时候手撸代码。

时间复杂度
  • 最好时间复杂度为O(nlog₂n)
  • 最坏时间复杂度为O(n²)
  • 平均时间复杂度为O(nlog₂n)
空间复杂度

需要额外的left和right临时空间所以空间复杂度为O(nlog₂n)

稳定性

代码第8行约定以第一个元素作为基准值,代码11-15行约定,当数据等于mid的时候放到right区间,所以相同元素位置前后不会改变。属于稳定的排序算法

快排实现方式二代码如下(不占用额外的空间消耗):

js 复制代码
function quickSort(arr, low, high) {
  if (low < high) {
    let pivotposition = partition(arr, low, high);
    quickSort(arr, low, pivotposition-1);
    quickSort(arr, pivotposition+1, high);
  }  
} 

function partition(arr, low, high) {
  let temp = arr[low];
  while(low < high) {
    // 此时左边位置为空,所以从右边去找,如果arr[high] >= temp移动指针接着往前找
    while(low < high && arr[high] >= temp){
      high--;
      continue;
    }
    // 此时左边位置为空,从右边去找,如果arr[high] < temp,则把它赋值给左边,此时右边的位置为空,跳出循环,重头再来
    while(low < high && arr[high] < temp){
      arr[low] = arr[high];
      low++;
      break;
    }
    // 此时右边为空,去左边找,找到arr[low] <= temp,移动指针接着往后找
    while(low < high && arr[low] <= temp){
      low++;
      continue;
    }
    // // 此时右边为空,去左边找,找到arr[low] > temp,把它赋值到右边,跳出循环,重头再来
    while(low < high && arr[low] > temp){
      arr[high] = arr[low];
      high--;
      break;
    }
  }
  arr[low] = temp;
  return low;
}
  • 我们遍历 p 到 r 之间的数据,将小于 pivot 的放到左边,将大于 pivot 的放到右边,将 pivot 放到中间。
  • 经过这一步骤之后,数组 p 到 r 之间的数据就被分成了三个部分,前面 p 到 q-1 之间都是小于 pivot 的,中间是 pivot,后面的 q+1 到 r 之间是大于 pivot 的。
  • 据分治、递归的处理思想,我们可以用递归排序下标从 p 到 q-1 之间的数据和下标从 q+1 到 r 之间的数据,直到区间缩小为 1,就说明所有的数据都有序了。
时间复杂度
  • 分区均衡,最好时间复杂度为O(nlog₂n)
  • 分区不均衡,最坏时间复杂度为O(n²)
  • 平均时间复杂度为O(nlog₂n)
空间复杂度

只需要一个temp空间,所以空间复杂度为O(1)

稳定性

涉及到左右位置的交换,所以排序过程中2个相同的数位置会交换,是不稳定的排序算法。

相关推荐
轻口味1 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀2 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
xiaoshiguang34 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡4 小时前
【C语言】判断回文
c语言·学习·算法
别NULL4 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇4 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯