《算法零基础100讲》(第37讲) 排序进阶 - 快速排序

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法零基础100讲》(第37讲) 排序进阶 - 快速排序相关的知识,希望对你有一定的参考价值。

零、写在前面

  这是《算法零基础100讲》 专栏打卡学习的第三十七天了。
  每天打卡的题,做不出来没关系,因为困难的题涉及知识点较多,后面还是会开放出来的,就像昨天的 最大公约数 那道题今天还是会有,所以不要着急,内容能看懂,能自己分析,能做出简单题,就可以打卡。
  在刷题的过程中,总结自己遇到的坑点,写出 「 解题报告 」 供他人学习,也是一种自我学习的方式。这就是经典的帮助他人的同时,成就自己。目前, 「 万人千题 」 社区 每天都会有五六篇高质量的 「 解题报告 」 被我 「 加精 」。如果觉得自己有能力的,也可以来发布你的 「 解题报告 」。千万级流量,你我共同拥有。

一、概念定义

  排序问题是最经典的算法问题了,一般一开始学的算法就是排序。但是由于 C/C++ 都有现成的库函数(C里是 qsort、C++里是sort),所以导致很多人就没有学排序算法本身,其实排序算法的思路非常经典,从最简单的学起,对日后学习复杂算法是非常有帮助的。这就是举一反三,粗类旁通的道理。
  从今天开始,我们来试着掌握每个排序算法的思路,今天是快速排序。
  快速排序,采用的是分治的思想,选择一个基准点,把所有小于基准点的数放到它左边,把所有大于基准点的数放到它右边,如图所示:

图示含义
■ 的柱形代表尚未排好序的数
■ 的柱形代表随机选定的基准数
■ 的柱形代表已经排序好的数
■ 的柱形代表正在遍历比较的数
■ 的柱形代表比基准数小的数
■ 的柱形代表比基准数大的数

  我们发现,首先随机选择了一个 7 作为「 基准数 」,并且将它和最左边的数交换。然后往后依次遍历判断,小于 7 的数为 「 绿色 」 ,大于 7 的数为「 紫色 」,遍历完毕以后,将 7 和 「 下标最大的那个比 7 小的数 」交换位置,至此,7的左边位置上的数都小于它,右边位置上的数都大于它,左边和右边的数继续递归求解即可。

二、题目描述

  给你一个 n ( n ≤ 1 0 5 ) n(n \\le 10^5) n(n105) 元素的整数数组 nums,请你将该数组升序排列。

三、算法详解

  整个算法的执行过程用 quickSort(a[], l, r)描述,代表 当前待排序数组 a a a,左区间下标 l l l,右区间下标 r r r,分以下几步:
  1) 随机生成基准点 p i v o x = P a r t i t i o n ( l , r ) pivox = Partition(l, r) pivox=Partition(l,r)
  2) 递归调用quickSort(a[], l, pivox - 1)quickSort(a[], pivox +1, r)
  3) Partition(l, r)返回一个基准点,并且保证基准点左边的数都比它小,右边的数都比它大;Partition(l, r)称为分区。

四、源码剖析

void Swap(int *a, int *b) 
    int tmp = *a;
    *a = *b;
    *b = tmp;


int Partition(int a[], int l, int r)
    int i, j, pivox; 
    int idx = l + rand() % (r - l + 1);        // (1) 
    pivox = a[idx];                            // (2) 
    Swap(&a[l], &a[idx]);                      // (3) 
    i = j = l + 1;                             // (4) 
                                               // 
    while( i <= r )                           // (5) 
        if(a[i] < pivox)                      // (6) 
            Swap(&a[i], &a[j]);                
            ++j;                               
        
        ++i;                                   // (7) 
    
    Swap(&a[l], &a[j-1]);                      // (8) 
    return j-1;



//递归进行划分
void QuickSort(int a[], int l, int r)
    if(l < r)
        int mid = Partition(a, l, r);
        QuickSort(a, l, mid-1);
        QuickSort(a, mid+1, r);
    


int* sortArray(int* nums, int numsSize, int* returnSize)
    QuickSort(nums, 0, numsSize-1);
    *returnSize = numsSize;
    return nums;

  • ( 1 ) (1) (1) 随机选择一个基准;
  • ( 2 ) (2) (2) pivox 代表基准值;
  • ( 3 ) (3) (3) 将基准和最左边的值交换;
  • ( 4 ) (4) (4) i i i j j j 是两个同步指针,都从 l + 1 l+1 l+1 开始; j − 1 j-1 j1 以后的数都是大于等于 基准值 的;
  • ( 5 ) (5) (5) 开始遍历整个排序区间, i i i 一定比 j j j 走的快,当 i i i 到达最右边的位置时,遍历结束;
  • ( 6 ) (6) (6) 如果比基准值小的,交换 a [ i ] a[i] a[i] a [ j ] a[j] a[j],并且自增 j j j
  • ( 7 ) (7) (7) 每次遍历 i i i 都需要自增;
  • ( 8 ) (8) (8) j j j 个元素以后都是不比基准值小的元素 ;

五、推荐专栏

🌳《画解数据结构》🌳

快速排序

六、习题练习

序号题目链接难度
1最小时间差★☆☆☆☆
2有序数组的平方★☆☆☆☆
3优势洗牌★★☆☆☆
4救生艇★★☆☆☆
👇🏻 关注公众号 观看 精彩学习视频👇🏻

以上是关于《算法零基础100讲》(第37讲) 排序进阶 - 快速排序的主要内容,如果未能解决你的问题,请参考以下文章

《算法零基础100讲》(第38讲) 排序进阶 - 希尔排序

《算法零基础100讲》(第32讲) 多维枚举 - 进阶

《算法零基础100讲》(第56讲) 哈希表进阶

《算法零基础100讲》(第45讲) 位运算 (位或) 进阶

《算法零基础100讲》(第47讲) 位运算 (异或) 进阶

《算法零基础100讲》(第34讲) 排序入门 - 选择排序