快速排序的思想是基于分治算法。
首先说明:快速排序是不稳定的!!
时间复杂度:O(nlogn)
给定区间[l,r]
算法思想:
第一步:确定分界点 可取q[l]、q[r]、q[(l+r)/2]、随机。 假设确定好一个数x
第二步(最难):重新划分区间,通过x将区间分为两部分,使第一个区间所有都小于等于x,第二个区间所有都大于等于x。
第三步:递归处理左右两段,先给左边排序,再给右边排序。
第四步:拼接两段。
我们可以用两个指针一个在区间左端点左侧,一个在区间右端点右侧,分别往中间走,直到i指针指向的数需要放到右区间,j指针指向的数需要放到左区间。
这个时候我们可以调用swap函数,可以手写实现swap。如此往复,直到i和j相遇为止。
代码实现如下:(以j划分!!!)
void quick_sort(int q[], int l, int r)
{
//如果我们的区间里没有数,或者只有一个数就不用排序了
if (l >= r)
return;
int x = q[l], i = l - 1, j = r + 1;
while (l < r)
{
do i++; while (q[i] < x);
do i--; while (q[j] > x);
if (i < j)
//交换两个数 或c++里直接调用swap(q[i],q[j])
{
int temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
进一步讨论:
快速排序属于分治算法!
分治算法都有三步:
1.分成子问题。
2.递归处理子问题。
3.子问题合并。
如何证明while循环结束后下面的式子成立?
注:q[l..j] <= x意为q[l],q[l+1]...q[j-1],q[j]的所有元素都<= x
证明如下
循环不变式:
1.初始化
循环开始之前,两个指针i,j均被初始化,均指向了边界的两侧。
其中
2.保持
执行循环体,所以i和j更新之后,下一次循环开始之前,循环不变式依然成立!
do i++; while (q[i] < x);
//会使得q[l...i-1]<=x,q[i]>=x
do i--; while (q[j] > x);
//会使得q[j+1...r]>=x,q[j]<=x;
if (i < j)
//交换两个数 或c++里直接调用swap(q[i],q[j])
{
int temp = q[i];
q[i] = q[j];
q[j] = temp;
}
//会使得q[l...i]<=x,q[j...r]>=x
注:由于使用的是do-while循环,i和j一定会自增一次,使循环继续下去。如果使用while循环,会出现死循环。
3.终止
循环结束时:i >= j
因为 i >= j ,
所以按j来划分 一定有
最后一轮循环的if语句一定不会执行
下面附一份用i划分的代码实现
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 >> 1];//注意是向上取整,因为向下取整可能使得x取到q[l]
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, i - 1), quick_sort(q, i, r);
}
完整代码:
#include<bits/stdc++.h>
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 (l < r)
{
do i++; while (q[i] < x);
do i--; while (q[j] > x);
if (i < j)
//交换两个数 或c++里直接调用swap(q[i],q[j])
{
int temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
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]);
}
return 0;
}