PTA basic 1045 快速排序 (25 分) c++语言实现(g++)
著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的 N 个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?
例如给定 N=5, 排列是1、3、2、4、5。则:
- 1 的左边没有元素,右边的元素都比它大,所以它可能是主元;
- 尽管 3 的左边元素都比它小,但其右边的 2 比它小,所以它不能是主元;
- 尽管 2 的右边元素都比它大,但其左边的 3 比它大,所以它不能是主元;
- 类似原因,4 和 5 都可能是主元。
因此,有 3 个元素可能是主元。
输入格式:
输入在第 1 行中给出一个正整数 N(≤105); 第 2 行是空格分隔的 N 个不同的正整数,每个数不超过 109。
输出格式:
在第 1 行中输出有可能是主元的元素个数;在第 2 行中按递增顺序输出这些元素,其间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
5
1 3 2 4 5
输出样例:
3
1 4 5
测试点0 测试用例通过
测试点1 少量数据主元判断
测试点2 0个主元时候的输出,要正确输出一个 0 和 一个空行
测试点3 4 5 大量数据主元判断是否正确
解题思路
1.题目本身是快速排序的主元选取,但是不需要手写快速排序,使用库函数sort()可以更快达到完成排序
2.其实题目考察的是观察主元特征,并准确判断特征的能力
3.主元的特征 (1)从待排序列头部到主元位置为止,主元一定是最大元素 (2) 待排序列的主元,已经在排序后的最终位置上
4.边界处理,比如没有主元,要输出0个主元的信息,然后再输出一个空行
5.
AC代码
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; int main(){ int n,i=0,flag; long max{0}; scanf("%d",&n); vector<long>fast_sortList(n,0); vector<long>PivotList; for(int i=0;i<n;i++){ scanf("%ld",&fast_sortList[i]); } vector<long>compare{fast_sortList};//将给定的数组拷贝到比较数组中 sort(compare.begin(),compare.end());//比较数组按升序排列 for(i=0;i<n;i++){ flag=0; if(fast_sortList[i]>max){max=fast_sortList[i];flag=true;}//如果当前元素比max大,则赋值给max,标记这个元素是目前的最大元素 if(compare[i]==fast_sortList[i]&&flag)PivotList.push_back(fast_sortList[i]); //如果这个元素的位置 处于 排序后的最终位置,那一定是主元 } sort(PivotList.begin(),PivotList.end());//主元列表升序排列 cout << PivotList.size()<<endl; if(PivotList.size()){//主元列表不为空时输出 for(i=0;i<PivotList.size()-1;i++){//输出前n-1个元素 cout << PivotList[i]<<" "; } cout << PivotList[i]<<endl;//最后一个输出结尾没有空格 }else{ cout<<endl;//0个主元时,要输出一个空行 测试点 2 } return 0; }
错误提交
1.第一次提交使用了快排逐个检查元素是否为主元,除了测试点1以外,都超时/错误了
2.第二次提交在快排基础上优化检查主元的方法,提交依然超时
1 //选取快排主元 // 初步思路是对每个元素进行一轮快排,位置不变的就是主元备选 2 //快排算法分两个部分,一个是递归划分子序列的部分,一个是子序列进行快排排序的部分,和归并类似,都是分而治之的思想 3 4 //递归划分部分 5 //递归子序列划分的基准在于pivot的选取,pivot由一轮快排排序产生,pivot之后和之前的元素分别构成两个序列,pivot前面和后面的一个元素分别成为子列的尾和头 6 //递归调用划分左右子序,直到low>=high 7 //一轮快排排序算法过程 8 9 //一轮快排排序中,首先记录pivot元素的位置index,暂存pivot元素为,严蔚敏版快排使用子序首元素作为pivot,所以pivot元素的位置默认为low 10 //然后以pivot为比较基准,从子序尾部开始比较,如果尾部比pivot大,则从后向前找(--high)到第一个比pivot小的元素的位置high 11 //将high位置的元素放入pivot元素的位置 也就是index(严蔚敏版 low )位置 12 //这个时候high位置就空了出来, 13 //然后比较头部元素和pivot,如果比pivot小,就从low位置开始向后找(low++),找到第一个比pivot元素大的元素的位置low 14 //将low位置的元素放入high位置 15 //循环结束条件为low>=high,这时两个标记相等,这个位置就是新的pivot位置 index 16 //将pivot放入index位置,index就是pivot在数列中最终的位置 17 18 //本题中要求出所有主元,如果一轮排序后选取的pivot的位置index没有发生变化,则说明这个元素是主元 19 //一个可能的思路 20 // 21 // 22 // 23 //快排的过程 24 //n个元素的序列中选取随机一个元素的位置k,标记当前位置k,并且暂存当前位置的数字为pivot,此时序列分为(0,k-1),k,(k+1,n-1) 25 26 //然后从后往前找比pivot小的数字放在temp位置,然后将标记向后移动一位 27 //严蔚敏版 快排一轮排序 28 //int partition(vector<int> presort,int low,int high){ 29 // int pivot=presort[low]; 30 // while(low<high){ 31 // while(presort[high]>pivot)--high; 32 // presort[low]=presort[high]; 33 // while(presort[low]<pivot)++low; 34 // presort[high]=presort[low]; 35 // } 36 // presort[low]=pivot; 37 // return low; 38 //} 39 //严蔚敏版 快排递归写法 40 //void quickSort(vector<int> preSort,int low,int high){ 41 // int pivot=partition(preSort,low,high); 42 // quickSort(preSort,low, pivot-1); 43 // quickSort(preSort, pivot+1, high); 44 //} 45 46 //第一次提交,不出意外的除了测试1全都超时了,接下来就是找技巧了 47 //第二步思路找到排序后的中间位置元素,用中间元素作为pivot,进行一轮快排,并与原数组进行比较,某个位置元素和原数组相等则说明是快排后位置不变,可能是主元 48 //第二次提交 测试点1通过, 测试点 2 3 4 5没有超时,但是答案错误,因此这个方法可行,但是需要增加正确率 49 // 50 51 52 #include <iostream> 53 #include <vector> 54 #include <string> 55 #include <algorithm> 56 using namespace std; 57 58 long partition(vector<long>& presort,long low,long high,long index){ 59 long pivot=presort[index]; 60 while(low<high){ 61 while((low<high)&&(presort[high]>pivot))--high; 62 presort[index]=presort[high]; 63 while((low<high)&&(presort[low]<pivot))++low; 64 presort[high]=presort[low]; 65 } 66 presort[low]=pivot; 67 return low;//pivot的最终位置 68 } 69 70 bool ispivot(vector<long>&presort,long low,long high,long index){ 71 long pivot=presort[index]; 72 bool flag=false; 73 while((low<high)&&(presort[high]>pivot))--high; 74 while((low<high)&&(presort[low]<pivot))++low; 75 if(low==high){ 76 flag=true; 77 } 78 return flag; 79 } 80 81 void markNumber(vector<long>preSort,long high,long pivotIndex,vector<long>&markList){ 82 vector<long>compare{preSort}; 83 partition(compare,0,high,pivotIndex); 84 for(int i=0;i<high;i++){ 85 if(compare[i]!=preSort[i]){ 86 markList[i]=0; 87 } 88 } 89 } 90 91 92 int main(){ 93 int n,i=0; 94 long temp;; 95 int max,min,pivotIndex,diff,maxIndex=0,minIndex=0; 96 scanf("%ld",&n); 97 vector<long>fast_sortList(n,0); 98 vector<long> markList(n,1); 99 vector<long>compare(n,0); 100 vector<long>PivotList; 101 scanf("%ld",&temp); 102 max=min=temp; 103 fast_sortList[i]=temp; 104 for(int i=1;i<n;i++){ 105 scanf("%ld",&temp); 106 // if(temp>max){max=temp;maxIndex=i;} 107 // if(temp<min){min=temp;minIndex=i;} 108 fast_sortList[i]=temp; 109 } 110 compare=fast_sortList; 111 //判断是否为主元 112 // for(i=1;i<n;i++){ 113 // long flag=partition(fast_sortList,0,n-1,i); 114 // if(flag==i)PivotList.push_back(fast_sortList[i]); 115 // } 116 117 for(i=0;i<n;i++){ 118 if(ispivot(fast_sortList,0,n-1,i))PivotList.push_back(fast_sortList[i]); 119 } 120 //第二次尝试 121 // long targetPivot=(max+min)/2; 122 // diff=fast_sortList[0]; 123 // pivotIndex=0; 124 // for(int i=0;i<n;i++){ 125 // if(diff>abs(fast_sortList[i]-targetPivot)){ 126 // diff=abs(fast_sortList[i]-targetPivot); 127 // pivotIndex=i; 128 // } 129 // } 130 // 131 // markNumber(fast_sortList,n-1,pivotIndex,markList); 132 // markNumber(fast_sortList,n-1,maxIndex,markList); 133 // markNumber(fast_sortList,n-1,minIndex,markList); 134 // 135 // for(i=0;i<n;i++){ 136 // if(markList[i]){ 137 // PivotList.push_back(fast_sortList[i]); 138 // } 139 // } 140 141 142 143 sort(PivotList.begin(),PivotList.end()); 144 cout << PivotList.size()<<endl; 145 for(i=0;i<PivotList.size()-1;i++){ 146 cout << PivotList[i]<<" "; 147 } 148 cout << PivotList[i]<<endl; 149 return 0; 150 }
第三次提交
//判断主元的方法 使用了快排的基本思路,如果在最终位置,则是主元
1 #include <iostream> 2 #include <vector> 3 #include <string> 4 #include <algorithm> 5 using namespace std; 6 7 bool ispivot(long *presort,int low,int high,int index){ 8 long pivot=presort[index]; 9 bool flag=false; 10 while((low<high)&&(presort[high]>pivot))--high; 11 while((low<high)&&(presort[low]<pivot))++low; 12 if(low==high){ 13 flag=true; 14 } 15 return flag; 16 } 17 int compare(const void *l,const void *r){ 18 return *(int*)l-*(int *)r; 19 } 20 21 int main(){ 22 int n,i=0,j=0; 23 long temp; 24 scanf("%d",&n); 25 long fast_sortList[n]; 26 long PivotList[n]; 27 scanf("%ld",&temp); 28 fast_sortList[i]=temp; 29 for(int i=1;i<n;i++){ 30 scanf("%ld",&temp); 31 fast_sortList[i]=temp; 32 } 33 34 for(i=0;i<n;i++){ 35 if(ispivot(fast_sortList,0,n-1,i)){PivotList[j]=fast_sortList[i];j++;} 36 } 37 38 qsort(PivotList,j-1,sizeof(long),compare); 39 cout << j <<endl; 40 for(i=0;i<j-1;i++){ 41 printf("%ld ",PivotList[i]); 42 } 43 cout << PivotList[i]<<endl; 44 return 0; 45 }