【图解】快速排序---超级容易理解的做法

    科技2022-07-10  261

    【图解】快速排序—超级容易理解的做法

    打算开始写算法专栏了,第一篇文章写什么呢?就快速排序吧!

    1.快排介绍

    快速排序的思想就是分治的思想,分治思想在算法中是非常常用也是非常重要的!一个问题,可以把它一分为二,然后再分别处理,依次类推,这就是分治的思想。

    那么快速排序是怎么一回事呢?我来告诉你:

    快速排序指的是,我们从一组数中任意选定一个数字(我们称这个数字叫基准值),然后经过一轮排序后使得小于基准值的数全部在基准值的左边;大于基准值的数全部在基准值的右边。这样我们从大的模块上来说就有序了,左边部分的最大值小于右边部分的最小值,然后再分别对左边部分快排,右边部分快排,直到有序

    2.举例说明

    看完这段话是不是不太好理解呢?没关系,我来举个简单的例子:

    有5个数字,分别是 3 1 2 4 5,利用快速排序将其变成升序序列

    那么,首先我们来选取一个基准值,基准值是任意的,你可以选第一个数作为基准值,也可以选最后一个,也可以选择中间的数,都可以!看你心情喽,但是如果你使用我接下来这种做法,那么为了确保万无一失,我建议你选取中间的数!那怎么选取中间的数呢?我们利用数组长度除以2 是不是就得到中间数的下标了呢

    //定义 l 为数组起始, r 为数组结尾 , 数组为 a[], 基准值为 x int l = 0, r = a.size() - 1; x = a[(l + r) / 2];

    这样,基准值 x 就得到了,那么这里你也可以这样写

    //我们知道,在 位运算中,右移一位就是除以2的意思,故可以使用右移 int l = 0 , r = a.size() - 1; x = a[l + r >> 1];

    现在,基准值找到了,在序列3 1 2 4 5中,通过l + r >> 1得到下标为2,故基准值x = a[2],即 数字2

    2.1 执行第一轮

    此时,我们利用双指针 i, j 分别代表左边指针和右边指针,分别从数组起始端和末尾段分别向中间移动,如果左边遇到大于2的数停止左边指针移动;如果右边遇到小于2的数,停止右边指针移动;此时如果i < j那么将两个数交换swap(a[i], a[j]),i指针和j指针继续移动, 直到 i > j,停止移动,此时第一轮结束。具体如下:

    第一次比较,3 > 2所以3应该是在右半边的,此时 i 指针停止后移;j指针所指向的 5 > 2, j指针前移

    再次比较,j指针所指向的 4 > 2, j指针继续前移

    此时,j 指针所指向的 2 ≯ 2,故 j 指针停止移动。判断 i< j ?如果符合,交换a[i], a[j]。如下 交换完成后,判断 I < j ?符合条件,继续移动 i指针指向的 1 < 2, 故 i指针继续移动 此时,i 指针指向的 3 ≮ 2,i指针停止移动;j 指针向前移动 j指针指向的1 ≯ 2,j指针停止移动;判断i< j ?不符合条件,第一轮结束

    2.2 递归左半边

    接下来开始分别递归左边和右边,左边的起始为 l = 0, r = j; 右边的起始为 l = j + 1, r = r

    对左边进行快排,选择基准值 x = l + r >> 1, 即(0 + 1 ) / 2 = 0, 所以a[0] = 2

    i指针指向的 2 ≮ 2,故 i指针停止移动;j指针指向的1 ≯ 2,故,j 指针停止移动;此时i< j, 交换a[i], a[j] 继续移动 i, j。此时,发现i和j指向的值均不满足条件,且j > i,不符合交换和循环条件,结束

    2.3 递归右半边

    同理:右半边也是如此,故总的排序结果为

    3.快排性质

    1. 快排的平均时间复杂度:O(nlogn) 2. 空间复杂度:O(logn) 3. 稳定性:由于此排序无法保证相等元素的相对位置不变,故它不是稳定的排序

    4. 完整代码

    #include <iostream> using namespace std; const int N = 100010; int q[N]; int n; //快速排序 void quick_sort(int q[], int l, int r) { if (l >= r) return; int i = l - 1, j = r + 1, x = q[l + r >> 1]; while(i < j) { do ++i; while(q[i] < x); do --j; while(q[j] > x); if (i < j) swap(q[i], q[j]); } quick_sort(q, l, j); quick_sort(q, j + 1, r); } int main() { cin >> n; for (int i = 0; i < n; i ++) scanf("%d",&q[i]); quick_sort(q, 0, n - 1); for (int i = 0; i < n; i ++) printf("%d ",q[i]); return 0; }
    Processed: 0.029, SQL: 8