六、快速排序
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;
}