机试笔记5--排序
一.使用sort来进行排序,它的时间复杂度是nlogn,所以能在1s内处理大概30w的数据
cmp(typename x,typename y)中是可以对x,y进行更改的,并不会影响到数组中的数,这也极大增加了cmp的适用性。
题型一.成绩排序(要求稳定)
输入任意(用户,成绩)序列,可以获得成绩从高到低或从低到高的排列,相同成绩都按先录入排列在前的规则处理。
分析:该题的考点是稳定排序,而sort排序是不稳定排序,解决的方法有两个,一是使用stable_sort函数,它的使用方法和sort一样。另一种方法是给每一个输入加一个递增的下标,然后进行二级排序,当值相同时,下标小的排在前面。
方法一:
在编写这个代码的过程中遇到了使用stable_sort报错的问题,发现是由于sort只能给int,char进行排序。解决这个问题也很简单,只需要更改cmp函数就可以
#include <iostream> #include <algorithm> #include <vector> using namespace std; typedef struct Student { string name; int score; }Student; bool downCmp(Student x,Student y) { return x.score>y.score; } bool upCmp(Student x,Student y) { return x.score<y.score; } int main() { int n,flag; cin >> n; cin >> flag; vector<Student> stu; Student s; for(int i=0;i<n;i++){ cin >> s.name >> s.score; stu.push_back(s); } int len = stu.size(); if(flag==0){ stable_sort(stu.begin(),stu.end(),downCmp); } else stable_sort(stu.begin(),stu.end(),upCmp); for(int i=0;i<stu.size();i++){ cout << stu[i].name << " "<<stu[i].score<<endl; } return 0; }
方法二:二级排序,在结构体中添加了一个变量num用于记录每一个变量的先后顺序。
#include <iostream> #include <algorithm> #include <vector> using namespace std; typedef struct Student { string name; int score; int num; }Student; bool downCmp(Student x,Student y) { if(x.score > y.score) return true; else if(x.score==y.score) return x.num<y.num; else return false; } bool upCmp(Student x,Student y) { if(x.score < y.score) return true; else if(x.score==y.score) return x.num<y.num; else return false; } int main() { int n,flag; cin >> n; cin >> flag; vector<Student> stu; Student s; for(int i=0;i<n;i++){ cin >> s.name >> s.score; s.num=i; stu.push_back(s); } int len = stu.size(); if(flag==0){ sort(stu.begin(),stu.end(),downCmp); } else sort(stu.begin(),stu.end(),upCmp); for(int i=0;i<stu.size();i++){ cout << stu[i].name << " "<<stu[i].score<<endl; } return 0; }
题型三.输入n个数进行排序,要求先按奇偶后按从小到大的顺序排序。核心还是在cmp函数上。
#include <iostream> #include <algorithm> using namespace std; bool cmp(int x,int y) { if(x%2>y%2) return true; else if(x%2==y%2) return x<y; else return false; } int main() { int n; cin >> n; int num; vector<int> arr; for(int i=0;i<n;i++){ cin >> num; arr.push_back(num); } sort(arr.begin(),arr.end(),cmp); for(int i=0;i<n;i++){ cout <<arr[i]<<" "; } cout << endl; return 0; }
题型四.字符串排序
编写一个程序,将输入字符串中的字符按如下规则排序(一个测试用例可能包含多组数据,请注意处理)。
规则 1 :英文字母从 A 到 Z 排列,不区分大小写。
如,输入: Type 输出: epTy
规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
如,输入: BabA 输出: aABb
规则 3 :非英文字母的其它字符保持原来的位置。
如,输入: By?e 输出: Be?y
分析:规则一只要在cmp中全部改成大写进行排序就可以
规则二使用stable_sort就可以
规则三只要不对非字母进行排序就可以
#include <iostream> #include <algorithm> #include <cstring> using namespace std; bool cmp(char x,char y) { if('a'<=x&&x<='z') x-='a'-'A'; if('a'<=y&&y<='z') y-='a'-'A'; return x<y; } int main() { char str[1005]; char t[1005]; while(gets(str)){ int j=0; for(int i=0;i<strlen(str);i++){ if(('a'<=str[i]&& str[i]<='z')||('A'<=str[i]&& str[i]<='Z')) t[j++]=str[i]; } stable_sort(t,t+strlen(t),cmp); int c=0; for(int i=0;i<strlen(str);i++){ if(('a'<=str[i]&& str[i]<='z')|| ('A'<=str[i]&& str[i]<='Z')) str[i] = t[c++]; } cout << str<<endl; } return 0; }
先输入你要输入的字符串的个数。然后换行输入该组字符串。每个字符串以回车结束,每个字符串少于一百个字符。 如果在输入过程中输入的一个字符串为“stop”,也结束输入。 然后将这输入的该组字符串按每个字符串的长度,由小到大排序,按排序结果输出字符串。
这里要注意的是在cin >> n和getline(cin,arr)之间要加一个getchar,因为cin之后输入缓冲区还有一个'\n'
整个过程如下
运行到 cin>>n,你输入一个数并按回车,cin把这个数给n并换行,此时输入缓冲区还有一个'\n',如果此时getline的话,getline会把这个换行符吞掉并换成'\0'给arr[1],所以arr[1]实际上是个空字符串。排序后这个空字符串会占第一行,所以就会出现隔一行输出排序后结果且少一个字符串的情况。
#include <bits/stdc++.h> using namespace std; bool cmp(string x,string y) { return x.size() <y.size(); } int main() { int n; while(cin >> n){ getchar(); string arr[n]; int i=0; for(;i<n;i++){ getline(cin,arr[i]); if(arr[i]=="stop"){ break; } } sort(arr,arr+i,cmp); for(int j=0;j<i;j++){ cout << arr[j] <<endl; } } return 0; }
一些特殊的情况
1.数据量很大,有几百万,这时候,nlogn的sort就无法满足要求了,如果待排数据的大小范围不是太大的话,可以使用简单的计数排序。时间复杂度为O(n)
2.找出数组中第K大的元素,可以利用快速排序中的分区算法
int findK(int K,int a[],int start,int end) { int pos; pos = partition(a,start,end); if(K>pos+1) return findK(K,a,pos+1,end); else if(K<pos+1) return findK(K,a,start,pos-1); else return a[pos]; }