快速排序
快速排序
主要思想:分治
具体步骤:
-
确定分界点x
- 取左边界q[l]
- 取中间点q[(l+r)/2]
- 取右边界q[r]
- 随机一个数
-
调整区间:
- 根据分界点x将整个区间划分为2半
- 使得第一个区间所有数都 <= x
- 第二个区间所有数都 >= x
- 这个数和x相等在左右两边都可以
-
递归处理左右两端区间
- 左右区间分别排好序整体就排好序了
具体代码实现
暴力做法
- 开两个额外的数组a[],b[]
- 把 <=x 的数存到a里面,把 >=x 的数存到b里面
- 使用双指针算法将a,b合并到一个数组
优美做法
不需要开辟额外的空间
将i向右移动,将j向左移动,当q[i] > x时i停止移动,q[j] < x 时j停止移动,然后交换q[i]和q[j]的值
当i > j时停止循环,整个数组已经排好序了
i指针前面的数一定<=3,j指针后面的数一定>=3
快速排序模板
代码
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
中之所以是<而不是<=的原因是
如排序1,3,2,2,5,如果选择<=,那么i是3,j也会直接跳到3,而选择<,i会停在3而j会停在2。
代码实现
/*
快速排序:
1)设k=a[0], 将k挪到适当位置,使比k小的元素在k左面,比k大的在k右面
2)把k左面的进行快速排序
3)把k右面的进行快速排序
*/
#include<iostream>
using namespace std;
const int MAXN = 100100;
int a[MAXN];
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
// 两个指针分别指向2个边界2侧,原因是第一次判断不管怎样都会
// 进入循环执行++,因为用的do while循环,所以是l-1和r+1
int i = l - 1, j = r + 1, x = q[l + r >> 1];
// mid = start + (end-start)/2;
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
// 递归处理左右两端
// 如果边界点取q[r],那么下面取j和j+1就会报错
// 如排序[1,2],i=0,j=1,x=1
// 1<=1,i->1, 2>1, j->1,区间就会变为(0,1)和(2,1)无限递归
// 同理如果取q[l],那么下面就不能是i-1和i
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; ++i) cin >> a[i];
quick_sort(a,0,n-1);
for(int i = 0; i < n; ++i) cout << a[i] << " ";
return 0;
}