从0到1|[001]快速排序

1. 算法介绍

快速排序是基于 分治 理念的一种算法,其基于冒泡排序,平均时间复杂度可以达到O(nlog2n)。

值得一提的是,该算法并不稳定。并且在极端情况下,时间复杂度可以达到O(n2)。

2. 算法思想

  • 在一轮快速排序中,将需要首先在数组中选取一个基准数字x。一般情况下,基准数字可以是左边界,右边界,中值或随机一个数组中的数字。

  • 引用两个指针ij,分别指向左边界和右边界。

  • i指针 向右 查询第一个 不小于x 的元素,而j指针则 向左 查询第一个 不大于x的元素,然后将两者互换。

    • 注意:在这类快排思想中,当i或j指针恰好指针指到了与x相等的值,则其也会停下!

    • 也就是说,若二者均指到了与相等的值,则其也会进行一次互换,虽然结果与原先相同!

  • 随后,将ij指针向下移动一位。

  • 重复上述两个步骤,直至ij两指针相遇,此时确认了x的位置。

    • 注意:在快速排序过程中,i指针的左侧元素必然不大于x,而j指针的右侧必然不小于x!

  • 利用快速排序,递归x的左子区和右子区,最终完成排序。

3. 算法模板

void quick_sort(int q[],int l,int r){
    
    if(l >= r) return;//(1)
    
    int x = q[l] , i = l - 1 , j = r + 1; //(2)
    
    while(i < j){
        do i++ ; while(q[i] < x); //(3)
        do j-- ; while(q[j] > x); //(4)
        if(i < j) swap(q[i],q[j]);        
    }
    
    quick_sort( q[] , l , j ); //(5)
    quick_sort( q[] , j + 1 , r); //(6)
    
    return;
} 

(1) 如果,左边界大于等于右边界,说明此时数组内元素个数为0或1,此时不需要排序,直接返回结果。

(2)i = l - 1 , j = r + 1,此处这样处理的理由如下:

观察下列代码,不难发现其利用do—while语句进行循环,这意味着ij两指针首先进行 下移一位 的操作,如此初始化ij两指针,首先下移一位,则ij指向了真正的数组边界,从而实现正确的排序结果。但,如果此处仅仅将其置为i = l, j = r,将ij两指针下移,则会错过边界值的判断。当数组下标较少时,甚至会报错。

(3)依据算法思想,i的任务就是找到第一个不小于x的值,其中也包括x本身。当do语句里的i++语句完称后,此时i指针已经指向了这个 不小于x 的值,同时,如果q[i] = xi指针也将指向该值。

若将do-while循环条件改为q[i]<=x,此时将会在上述基础上情况多循环一轮,那么当q[i]=x时,i将指向值为x元素的下一个元素。这意味着,如果x恰巧取于右边界,数组将会越界。

(4)与(3)相同。

(5)此处是一个更新。递归调用,继续快速排序其左子区和右子区。

4. 算法难点

该算法难于理解的是x的取值和递归语句的使用。

从结论上来说:

如果,x=q[l],则后续递归语句必须写为:

quick_sort(q,l,j);quick_sort(q,j+1,r)

如果,x=q[r]或x=q[(l+r+1)/2],则后续递归语句必须写为:

quick_sort(q,l,i-1);quick_sort(q,i,r)

4. 算法实现

#include<iostream>
using namespace std;
​
const int N = 1e6 + 10;
​
int q[N];
int num = 0 ;
​
void quick_sort(int q[],int l,int r){
    
    if(l >= r) return;//(1)
    
    int x = q[l] , i = l - 1 , j = r + 1; //(2)
    
    while(i < j){
        do i++ ; while(q[i] < x); //(3)
        do j-- ; while(q[j] > x); //(4)
        if(i < j) swap(q[i],q[j]);        
    }
    
    quick_sort( q , l , j ); //(5)
    quick_sort( q , j + 1 , r); //(6)
    
    return;
} 
​
int main(){
​
    scanf("%d",&num);
    for(int i = 0 ; i < num ; i++){
        scanf("%d",&q[i]);
    }
    
    quick_sort( q , 0 , num - 1);
    
    for(int i = 0 ; i < num ; i++){
        printf("%d ",q[i]);
    }
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值