经典排序算法之实现(五)

六、快速排序

1、基本思想

       选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

2、实例

例如关键字序列        ( 52, 49, 80, 36, 14, 75, 58, 97, 23, 61 )
经第1趟快速排序之后为   ( 23, 49, 14, 36) 52 (75, 58, 97, 80, 61 )
经第2趟快速排序之后为   ( 14) 23 (49, 36) 52 (61, 58) 75 (80, 97 )
经第3趟快速排序之后为   ( 14, 23, 36, 49, 52, 58, 61, 75, 80, 97 )

3、代码

/*
 *泡排序是通过一趟"起泡"选定关键字最大的记录,所有剩余关键字均小于它的记录继续进行排序,
 *快速排序则是通过一趟排序选定一个关键字介于"中间"的记录,
 *从而使剩余记录可以分成两个子序列分别继续排序,通常称该记录为"枢轴"。
 *如右图所示,假设一趟快速排序之后枢轴记录的位置为 i,
 *则得到的无序记录子序列(1) R[s..i-1] 中记录的关键字均小于枢轴记录的关键字,
 *反之,得到的无序记录子序列(2)R[i+1..t] 中记录的关键字均大于枢轴记录的关键字,
 *由此这两个子序列可分别独立进行快速排序。
 *
 *例如,关键字序列    ( 52, 49, 80, 36, 14, 75, 58, 97, 23, 61 )
 *经第1趟快速排序之后为 ( 23, 49, 14, 36) 52 (75, 58, 97, 80, 61 )
 *经第2趟快速排序之后为 ( 14) 23 (49, 36) 52 (61, 58) 75 (80, 97 )
 *经第3趟快速排序之后为 ( 14, 23, 36, 49, 52, 58, 61, 75, 80, 97 )
 *
 *
 *一趟快排也称"一次划分",即将待排序列 R[s..t]"划分"为两个子序列R[s..i-1] 和 R[i+1..t],
 *i 为一次划分之后的枢轴位置。可以取待排序列中任何一个记录作为枢轴,但为方便起见,
 *通常取序列中第一个记录 R[s] 为枢轴,以它的关键字作为划分的依据。
 *划分可如下进行:设置两个指针 low 和 high,分别指向待排序列的低端 s 和高端 t。
 *若 R[high].key<R[s].key,则将它移动至枢轴记录之前;
 *反之,若 R[low].key>R[s].key,则将它移动至枢轴记录之后,并为避免枢轴来回移动,
 *可先将枢轴 R[s] 暂存在数组的闲置分量 R[0] 中。
 *
 *
 * 
 *注意:R[0]为数组的闲置分量
 *
 */
#include <iostream>
using namespace std;

int Partition( int *R, int low, int high){
    // 对记录子序列 R[low..high] 进行一趟快速排序,并返回枢轴记录
    // 所在位置,使得在它之前的记录的关键字均不大于它的关键字,
    // 而在它之后的记录的关键字均不小于它的关键字
    R[0] = R[low]; // 将枢轴记录移至数组的闲置分量
    int pivotkey = R[low];  // 枢轴记录关键字
    cout << endl << "pivotkey : " << pivotkey << endl;
    while(low < high){    // 从表的两端交替地向中间扫描
        while( low<high && R[high]>=pivotkey ){
            --high;
        }
        if(low < high){//需要进行这样的判断,如果是由于low>=high而退出的循环,不需要移动数据
            R[low++] = R[high]; // 将比枢轴记录小的记录移到低端
            //cout << "移动的hign数据:" << R[high] << endl;
        }    
        while (low<high && R[low]<=pivotkey )
            ++low;
        if(low < high){
            R[high--] = R[low];    // 将比枢轴记录大的记录移到高端
            //cout << "移动的low数据:" << R[low] << endl;
        }    
    } // while
    R[low] = R[0];    // 枢轴记录移到正确位置
    //cout << "返回的pivotkey: " << low << endl;
    for(int i = 1; i<=10; i++){
        cout << R[i-1] << " ";    
    }
    return low;    // 返回枢轴位置
} 
void QSort(int *R, int s, int t ){
    // 对记录序列 R[s..t] 进行快速排序
    if (s < t){    // 长度大于1
        int pivotloc = Partition(R, s, t);// 对 R[s..t] 进行一趟快排,并返回枢轴位置
        QSort(R, s, pivotloc-1);//对低子序列递归进行排序
        QSort(R, pivotloc+1, t);//对高子序列递归进行排序
    }
}
int  main(){
    int li[10] = {0,38,65,97,76,13,27,48,55,4};
    cout<<"注意:R[0]为数组的闲置分量"<<endl;
    for(int i = 1; i<=10; i++){
        cout << li[i-1] << " ";    
    }
    cout << endl;
    QSort(li,1,9);
    cout << endl;
    for(int i = 1; i<=10; i++){
        cout << li[i-1] << " ";    
    }
    cout << endl;
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值