快速排序原理和实现(图文讲解)

快速排序是一种常用的排序算法,快速排序也使用了分而治之(divide /dɪˈvaɪd/ and conquer /ˈkɒŋkər/ 简称D&C)。分而治之是一种思路,它是一种递归思想,每个递归函数都有两部分:

  1. 基线条件(base case)
  2. 递归条件(recursive case) /rɪˈkɜːsɪv/

递归条件指的是函数调用自己,而基线条件则指的是函数不再调用自己,从而避免形成无限循环。

function fibonacci(n) {
    if (n <=2) {  // n <=2 基线条件
        return 1
    };
    return fibonacci(n - 2) + fibonacci(n - 1);  // n>2 为递归条件
};
fibonacci(10)  //55

有了递归的基础接下来我们再来看下快速排序的写法!

1.快速排序易懂版

有下图这么一个数组[4, 5, 1, 6, 9, 22, 6]
在这里插入图片描述
我们先确定基准点,那么我们取中间值为基准点!
在这里插入图片描述
然后以基准点为参照值对数组进行排序,比6小的放左边,比6大的放右边!
在这里插入图片描述
第一轮排序完成了,我们开始对左右两边再进行排序,先看左边的!
在这里插入图片描述
和上面一样,先取中间值为基准点!
在这里插入图片描述
然后以基准点为参照值对数组进行排序,比5小的放左边,比5大的放右边,这里4,1都比5小,所以都在左边,右边没有值!
在这里插入图片描述

接下来对1,4这两个元素进行排序,先取基准点!

在这里插入图片描述
以基准点为参照值对数组进行排序,比4小的放左边,比4大的放右边,右边也没有值!

在这里插入图片描述

再看右边的数组!
在这里插入图片描述
先取中间值为基准点!
在这里插入图片描述
然后以基准点为参照值对数组进行排序,比22小的放左边,比22大的放右边,这里9,6都比22小,所以都在左边,右边也没有值!

在这里插入图片描述
接下来对6,9这两个元素进行排序,先取基准点!
在这里插入图片描述
以基准点为参照值对数组进行排序,比9小的放左边,比9大的放右边,右边也没有值!
在这里插入图片描述
最终合并数组完成整个排序(因为数字比较少,我把所有的步骤都列出来了)!
在这里插入图片描述
上面是快速排序的一个完整的步骤!那么我们代码中怎么实现!

  1. 明确基线条件和递归条件(当数组的元素为空或者只包含一个元素,在这种情况下,只需原样返回数组,根本就不用排序,那么当数组的元素大于1时就是递归条件)。
  2. 选择好基准点为parseInt(arr.length / 2)。
  3. 创建左边一个数组left,右边一个数组为right,当比基准点大时放进right里面,比基准点小时放进left里面。
  4. 然后对left,right 不断的重复2,3步骤。
  5. 合并数组。
function quickSort(arr) {
   let temp = arr.slice(0), //复制一个数组
       left = [],
       right = [],
       middle = temp[parseInt(temp.length / 2)]; //取基准点
   if (temp.length < 2) {//递归的基线条件
       return temp;
   };
   temp.splice(parseInt(temp.length / 2), 1); //数组去掉基准点这个元素
   for (var i = 0; i < temp.length; i++) {
       if (temp[i] < middle) {
           left.push(temp[i]) //比基准点小时放进left里面
       } else {
           right.push(temp[i])//比基准点大时放进right里面
       };
   };
   return quickSort(left).concat([middle]).concat(quickSort(right));//递归并合并数组
};
console.log(quickSort([4, 5, 1, 6, 9, 22, 6])); //[1, 2, 5, 6, 6, 9, 22]

上面这种快速排序比较易懂,但是每次都要创建left,right数组,这样就增加了空间复杂度!效率就降低了!

2.快速排序易变种版

我们还是要先找基准点,那么这里的基准点就选第一个元素,上面我们是创建left,right数组来区分,这里可以用两个变量i和j,分别指向序列最左边和最右边,你可以理解i是小于基准点的值,j是大于基准点的值,还是用上面的数组[4, 5, 1, 6, 9, 22, 6]
在这里插入图片描述

这里基准点是4,首先,变量j向左移动,当小于基准点4时停下脚步!,然后变量i向右移动,当大于基准点4时候停下脚步!
在这里插入图片描述
这里变量i的值是5,变量j的值是1,交换I,j的值!
在这里插入图片描述
然后j再向左移动找比基准点4小的值,找到了1停下脚步,接着i向右移动找比基准点4大的值,当碰到了j停下脚步!
在这里插入图片描述
最后交换基准点和i或者j的值(它们相等)
在这里插入图片描述
第一轮排序就完成了,4左边是比4小的,4右边是比4大的,左边右边进行重复上面的操作!

那么我们代码中怎么实现!

  1. 明确基线条件和递归条件(如果数组只有一个元素,根本就不用排序,那么当数组的元素大于1时就是递归条件)。
  2. 选择好基准点为arr[0]。
  3. 创建两个变量i和j,分别指向序列最左边和最右边。
  4. 不断的重复2,3步骤。
  let arr = [4, 5, 1, 6, 9, 22, 6];
 function quickSort(arr, left, right) {
     let i = left,
         j = right,
         middle = arr[left];//取基准点
     if (left >= right) {//如果数组为空或者只有一个元素,跳出递归
         return;
     };
     while (i < j) {//当i=j跳出循环
         while (arr[j] > middle && i < j) {//从右向左找第一个比基准点小的值
             j--;
         };
         while (arr[i] <= middle && i < j) {//从左向右找第一个大于等于基准点的值,注意这里可以相等,是为了保证基准点的位置不变
             i++;
         };
         if (i < j) {//交换值
             let temp = arr[i];
             arr[i] = arr[j];
             arr[j] = temp;
         }
     };
     当i和j相等,再和基准值交换值
     arr[left] = arr[i];
     arr[j] = middle;
     quickSort(arr, left, i - 1);//递归基准点左边的数组,并且当left>=i-1跳出递归
     quickSort(arr, i + 1, right);//递归基准点右边的数组,并且当i+1>=right跳出递归
 };
 quickSort(arr, 0, arr.length - 1);//[1, 4, 5, 6, 6, 9, 22]

以上两种方法都可以实现快速排序,只不过是实现的方式不一样而已,快速排序的平均运行时间为O(n log n),最糟情运行时间为 O(n2),不懂的话可以点击算法的时间复杂度(大O表示法)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值