首先,假设有一个原始杂乱的数列,权值为 : 3、1、3、6、4、0 。
首先在这个有6个值的数列,先选取一个基准数,这个基准数选法不唯一。
(我们这里的基准数选择数列的第一个就好,其他原理也相同,算法程序略不同)。
- 初始基准数: 3。
- L和R表示当前数列的第一个元素的位置,最后一个元素的位置。
- 图中有两个指针分别写着左和右,初始时指向数列的 L-1 和 R+1的位置。
快排的基本做法:
第一趟-移动左指针:
移动左指针,当遇到第一个不小于基准数的数,那么停止。到3成立,所以停止。
第一趟-移动右指针:
移动右指针,当遇到第一个不大于基准数的数,那么停止。这里,到0这已经成立。
第一趟交换:交换
然后此时:如果左指针在右指针的左边,那么交换 3 和 0。如果不在,会有另外的选择。
第二趟-移动左右指针:
和第一趟是同理的,移动完毕后的结果如图。
第二趟-是否交换?
此时发现右指针在左指针左侧了,不符合了左指针在右指针的左边的条件,所以不交换。
此时的操作:把这个大数列分成两个小数列,从L到右指针所有的数作为一个新数列A,从左指针到R的数作为一个新的数列B。
新的数列A:
新数列B:
分治:A和B遵从同样的规则。
注意!此时的基准数,是A和B各自的基准数了,新的基准数。A的基准数:0 B的基准数:6。
以数组A为例A,流程:
移动指针,分别到数值为0的位置----》并且此时符合交换条件,左指针在左,那么交换0、0,所以没什么大变化。
继续移动指针。右指针跑到了更左边的位置。我们需要对A继续分治。
根据指针位置,分出新的分组:A1、A2
此时A1就剩一个元素了,那么我们就不管他了
A2还需要最后的移动,A2的基准值:1
左指针在更左边,进行交换。得到最后的A2数列: 0 、1
A = A1 + A2 = { 0、0、1}
B = {3、4、6}
总数列 = A + B = {0、0、1、3、4、6}
总结:快排几个重要的点
- 基准值的选取
- 移动指针
- 是否交换?
- 分治
下面给出快排模板:
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int n;
int q[N];
void quick_sort(int q[], int l, int r)
{
if(l >= r ) return ;//如果到头了就停止
int x = q[l], i = l -1, j = 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()
{
scanf("%d", &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]);
}