快速排序

快速排序

主要思想:分治
具体步骤:
  1. 确定分界点x

    • 取左边界q[l]
    • 取中间点q[(l+r)/2]
    • 取右边界q[r]
    • 随机一个数
  2. 调整区间:

    • 根据分界点x将整个区间划分为2半
    • 使得第一个区间所有数都 <= x
    • 第二个区间所有数都 >= x
    • 这个数和x相等在左右两边都可以
  3. 递归处理左右两端区间

    • 左右区间分别排好序整体就排好序了
具体代码实现
暴力做法
  1. 开两个额外的数组a[],b[]
  2. 把 <=x 的数存到a里面,把 >=x 的数存到b里面
  3. 使用双指针算法将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;
}
posted @ 2020-10-22 21:49  晓尘  阅读(130)  评论(0)    收藏  举报