快速排序1(算法)

快速排序(标准版)

思想:

分治思想

算法思路:

  • 确定分界点 q[l],q[(l+r)/2],q[r],随机
  • 调整区间:确定一个分界点x,使得所有左边的数都小于等于x,所有右边的数都大于等于x
  • 递归处理左右两段内容

调整区间方法一:(暴力的调整区间,时间复杂度O(n))

  • 创建两个数组a[],b[]

  • q[l~r]:

    • q[i]<=x x->a[]
    • q[i]>x x->b[]
  • a[]->q[] , b[] -> q[]

调整区间方法二:

  • 使用两个指针,指向两端,同时向x的方向走
  • 左指针指到一个大于x的数后停止,右指针指到一个小于x的数后停止
  • 两个数字交换
  • 左右指针都走到x时,确保左边的数字都小于等于x,右边的数字都大于等于x

例题:

题目描述:

给定你一个长度为n的整数数列。

请你使用快速排序对这个数列按照从小到大进行排序

并将排好序的数列按顺序输出。

输入格式

输入共两行,第一行包含整数 n。

第二行包含 n 个整数(所有整数均在1~109109范围内),表示整个数列。

输出格式

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

数据范围

1≤n≤100000

输入样例:

5
3 1 2 4 5
输出样例:

1 2 3 4 5

代码1:

//快速排序
#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) q[i]^=q[j],q[j]^=q[i],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]);
    return 0;
}

注意:如果选取的x为端点值,可能会超时

原因:当给定的序列有序时,如果每次选择区间左端点进行划分,每次会将区间[L, R]划分成[L, L]和[L + 1, R],那么相当于每次递归右半部分的区间长度只会减少1,所以就需要递归 n−1次了,时间复杂度会达到 n2。但每次选择区间中点或者随机值时,划分的两个子区间长度会比较均匀,那么期望只会递归 logn层。

解决办法:**x由端点值修改为中间值

AC代码

#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+r)/2],i=l-1,j=r+1;
    while(i<j){
        do i++;while(q[i]<x);
        do j--;while(q[j]>x);
        if(i<j) q[i]^=q[j],q[j]^=q[i],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]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章