快速排序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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章