目录
问题描述
要求根据给定输入,按照快速排序算法(殷人昆第2版教材 P349 程序8-12)进行排序,输出排序结果和median3的返回值。在划分时,以当前序列的首位元素、中间位置元素和最末元素的中间值为枢轴,记为median3。注意,如median3不在首位,需要和首位元素交换位置。
注:1,cutoff值为5,不足cutoff使用插入排序。
2,输入、输出格式参见测试用例0。
| 测试输入 | 期待的输出 | 时间限制 | 内存限制 | 额外进程 | |
|---|---|---|---|---|---|
| 测试用例 1 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
| 测试用例 2 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
问题分析
我们采用快速排序优化版——选基准记录的三者取中快速算法。
每次在最左边、中间和最右边选取次小值作为基准元素,并将基准元素换到倒数第二个位置。
置两个移动下标分别从左、右向中心遍历,若遇到左边值比基准元素大的或者右边值比基准元素小的就交换。最后两下标指向相同的元素,把该元素和基准元素互换位置。
这样就把原序列按基准元素分成左右两边,左边的元素都小于基准元素,右边的元素都大于基准元素。
然后再分别在左右两边排序,递归即可。
问题解决
定义全局变量
#define N 10010
int num[N]; //需要排序的数组
int medium[N]; //mid数组
int countmid=0; //mid个数
定义交换函数
void swapp(int x,int y) //直接传下标
{
int temp;
temp=num[x];
num[x]=num[y];
num[y]=temp;
}
求每次基准元素的函数
int median3(int left,int right)
{
int mid=(left+right)/2;
if(num[left]>num[mid]) //这三轮if完了之后能保证最左、中、最右三个元素按从小到大排序
{
swapp(left,mid);
}
if(num[left]>num[right])
{
swapp(left,right);
}
if(num[mid]>num[right])
{
swapp(mid,right);
}
swapp(mid,right-1); //把中间元素换到倒数第二个
medium[countmid]=num[right-1]; //mid值计入数组
countmid++;
return num[right-1]; //返回本轮基准元素
}
定义划分函数
int Part(int left,int right)
{
if(right-left<5) //题目要求小于5个数时直接插入排序
{
Insert(left,right); //此函数稍后定义
return -1;
}
int pivot=median3(left,right);//拿到基准元素
int i=left;
int j=right-1;
while (i<j)
{
while(i<j && num[++i]<pivot); //一直遍历到左边某元素大于等于基准元素后跳出
while(i<j && num[--j]>pivot); //一直遍历到右边某元素小于等于基准元素后跳出
swapp(j,i); //交换两元素
}
swapp(right-1,i); //最后交换基准元素和两指针同时指向的元素
return i; //返回基准元素下标
}
划分函数中用到的insert函数如下
void Insert(int left,int right) //直接插入排序
{
int i,j,temp;
for(i=left;i<=right;i++)
{
if(num[i]<num[i-1])
{
temp=num[i];
for(j=i-1;j>=left && temp<num[j];j--)
{
num[j+1]=num[j];
}
num[j+1]=temp;
}
}
}
快速排序函数
void Quick(int left,int right)
{
int mid;
if(left<right)
{
mid=Part(left,right);
if(mid!=-1){ //不用直接排序时说明数据还很多,要继续递归快速排序
Quick(left,mid-1);
Quick(mid+1,right);
}
}
}
main函数
int main()
{
int l=0;
string t; //注意读入数据的方法
while (cin>>t)
{
if (t == "#") break;
num[l] = stoi(t); //stoi()是将字符串类型转化为整型
l++;
}
Quick(0,l-1);
cout<<"After Sorting:"<<endl;
for(int i=0;i<l;i++)
{
cout<<num[i]<<" ";
}
cout<<endl;
cout<<"Median3 Value:"<<endl;
if(countmid==0) cout<<"none"<<endl;
else{
for(int i=0;i<countmid;i++)
{
cout<<medium[i]<<" ";
}
cout<<endl;
return 0;
}
}
可以积累一下连续读入不确定位数的整数直到读入某字符时停止读数据的方法。
其中stoi()是将字符类型串转化为整型的内置函数
完整代码如下:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#define N 10010
using namespace std;
int num[N];
int medium[N];
int countmid=0;
void Insert(int left,int right)
{
int i,j,temp;
for(i=left;i<=right;i++)
{
if(num[i]<num[i-1])
{
temp=num[i];
for(j=i-1;j>=left && temp<num[j];j--)
{
num[j+1]=num[j];
}
num[j+1]=temp;
}
}
}
void swapp(int x,int y) //直接传下标
{
int temp;
temp=num[x];
num[x]=num[y];
num[y]=temp;
}
int median3(int left,int right)
{
int mid=(left+right)/2;
if(num[left]>num[mid])
{
swapp(left,mid);
}
if(num[left]>num[right])
{
swapp(left,right);
}
if(num[mid]>num[right])
{
swapp(mid,right);
}
swapp(mid,right-1);
medium[countmid]=num[right-1];
countmid++;
return num[right-1];
}
int Part(int left,int right)
{
if(right-left<5)
{
Insert(left,right);
return -1;
}
int pivot=median3(left,right);//拿到基准元素
int i=left;
int j=right-1;
while (i<j)
{
while(i<j && num[++i]<pivot);
while(i<j && num[--j]>pivot);
swapp(j,i);
}
swapp(right-1,i);
return i;
}
void Quick(int left,int right)
{
int mid;
if(left<right)
{
mid=Part(left,right);
if(mid!=-1){
Quick(left,mid-1);
Quick(mid+1,right);
}
}
}
int main()
{
int l=0;
string t;
while (cin>>t)
{
if (t == "#") break;
num[l] = stoi(t);
l++;
}
Quick(0,l-1);
cout<<"After Sorting:"<<endl;
for(int i=0;i<l;i++)
{
cout<<num[i]<<" ";
}
cout<<endl;
cout<<"Median3 Value:"<<endl;
if(countmid==0) cout<<"none"<<endl;
else{
for(int i=0;i<countmid;i++)
{
cout<<medium[i]<<" ";
}
cout<<endl;
return 0;
}
}
本文介绍了如何使用快速排序算法优化版,通过选取基准元素为序列首位、中间和最末元素的中间值(median3),实现快速排序并计算median3值。当序列长度小于5时,采用插入排序。详细展示了C++代码实现过程。

541

被折叠的 条评论
为什么被折叠?



