首页 > 编程知识 正文

快速排序 原理,快速排序法排序过程解

时间:2023-05-06 21:00:16 阅读:194885 作者:2184

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

基线条件(base case)递归条件(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时就是递归条件)。选择好基准点为parseInt(arr.length / 2)。创建左边一个数组left,右边一个数组为right,当比基准点大时放进right里面,比基准点小时放进left里面。然后对left,right 不断的重复2,3步骤。合并数组。 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时就是递归条件)。选择好基准点为arr[0]。创建两个变量i和j,分别指向序列最左边和最右边。 不断的重复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表示法)

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。