AcWing 785. 快速排序

138 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

题目

给定你一个长度为 n 的整数数列。 请你使用快速排序对这个数列按照从小到大进行排序。 并将排好序的数列按顺序输出。

输入格式

输入共两行,第一行包含整数 n。 第二行包含 n 个整数(所有整数均在 1∼10^9 范围内),表示整个数列。

输出格式

输出共一行,包含 n 个整数,表示排好序的数列。

数据范围

1 ≤ n ≤ 100000

输入样例:

5 3 1 2 4 5

输出样例:

1 2 3 4 5

思路

快速排序的模板

image.png

1130_1196bbb27a-2.gif

快速排序属于分治算法

分治算法步骤:

1.分成子问题

2.递归处理子问题

3.子问题合并

Snipaste_2022-07-02_19-06-25.png

Snipaste_2022-07-02_19-07-48.png

快速排序

有数组 arr, 左端点 l, 右端点r

确定划分边界 x

将 arr 分为 <=x 和 >=x 的两个小数组

i 的含义: i 之前的元素都 ≤ x, 即 q[l..i−1] ≤x

j 的含义: j 之后的元素都 ≥ x, 即 q[j+1..r] ≥x

结论: while 循环结束后, q[l..j] ≤x,q[j+1..r]≤x,

简单不严谨证明:

while 循环结束时, i≥j 若 i>j , 显然成立

若 i=j ∵ 最后一轮循环中两个 do−while 循环条件都不成立

∴ arr[i]≥x,arr[j]≤x

∴ arr[i] = arr[j] = x

∴ 结论成立

快速排序模板

void quick_sort(int arr[],int l,int r){
   //递归的终止情况
   if(l >= r) return;  
   //分成子问题
   int x = arr[l + r + 1 >> 1],i = l - 1,j = r + 1; 
   while(i < j){ 
       do i++;while(arr[i] < x);
       do j--;while(arr[j] > x);
       if(i < j){
           int temp = arr[i];
           arr[i] = arr[j];
           arr[j] = temp;
       }
   }
   //递归处理子问题
   quick_sort(arr,l,i - 1);
   quick_sort(arr,i,r);
   //子问题合并,快速排序无需考虑此操作
}

ac代码

#include<iostream>
using namespace std;
int n;
const int N = 100010;
int arr[N];
void quick_sort(int arr[],int l,int r){
    if(l >= r) return;
    int x = arr[l + r + 1 >> 1],i = l - 1,j = r + 1;
    while(i < j){
        do i++;while(arr[i] < x);
        do j--;while(arr[j] > x);
        if(i < j){
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    quick_sort(arr,l,i - 1);
    quick_sort(arr,i,r);
}
int main(){
    cin >> n;
    for(int i = 0;i < n;i++) cin >> arr[i];
    quick_sort(arr,0,n - 1);
    for(int i = 0;i < n;i++)cout << arr[i] << " ";
    return 0;
}