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 }

 



posted @ 2021-05-07 20:35  keiiha  阅读(227)  评论(0编辑  收藏  举报