【图解】快速排序—超级容易理解的做法
打算开始写算法专栏了,第一篇文章写什么呢?就快速排序吧!
快速排序的思想就是分治的思想,分治思想在算法中是非常常用也是非常重要的!一个问题,可以把它一分为二,然后再分别处理,依次类推,这就是分治的思想。
那么快速排序是怎么一回事呢?我来告诉你:
快速排序指的是,我们从一组数中任意选定一个数字(我们称这个数字叫基准值),然后经过一轮排序后使得小于基准值的数全部在基准值的左边;大于基准值的数全部在基准值的右边。这样我们从大的模块上来说就有序了,左边部分的最大值小于右边部分的最小值,然后再分别对左边部分快排,右边部分快排,直到有序
看完这段话是不是不太好理解呢?没关系,我来举个简单的例子:
有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
此时,我们利用双指针 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 ?不符合条件,第一轮结束
接下来开始分别递归左边和右边,左边的起始为 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,不符合交换和循环条件,结束
同理:右半边也是如此,故总的排序结果为