算法基础知识——排序与查找
目录:
- 基础知识
- 排序(基本类型、结构体或类)
- 查找(线性查找、二分查找)
- 应用实例
- 排序【华中科技大学】
- 成绩排序【清华大学】
- 成绩排序2【清华大学】
- 特殊排序【华中科技大学】
- 整数奇偶排序【北京大学】
- 小白鼠排队【北京大学】
- 奥运拍讯问题【浙江大学】
- 找x【浙江大学】
- 查找【北京邮电大学】
- 找最小数【北京邮电大学】
- 打印极值点下标【北京大学】
- 找位置【华中科技大学】
一、基础知识
1、排序
- 基本类型的排序:对整型、浮点型等计算机编程语言内置的基本类型进行排序
- 结构体或类的自定义排序:
- 方法一:设计比较函数
- 方法二:在结构体或类的内部重载小于号
2、查找
- 先通过排序,方便查找。
- 查找的基本要素:
- 查找空间(解空间):在查找空间中找寻复合要求的解。
- 查找目标:需要一个目标来判断查找空间中的各个元素是否符合要求,以便判断查找活动是否成功。
- 查找方法:利用某种特定的策略在查找空间中查找各个元素。
- 常用查找方法:
- 线性查找:多次(m次)查找时间复杂度:O(mn)
- 二分查找:多次(m次)查找时间复杂福:O(nlogn + mlogn)
- 当m达到一定程度时,二分查找的性能远优于线性查找。
二、应用实例
1、题目描述:对输入的n个数进行排序并输出。【华中科技大学】
- 输入格式:输入的第一行包括一个整数n(1<=n<=100)。接下来的一行包括n个整数。
- 输出格式:可能有多组测试数据,对于每组数据,将排序后的n个整数输出,每个数后面都有一个空格。每组测试数据的结果占一行。
- 样例输入:
- 4
- 1 4 3 2
- 样例输出:
- 1 2 3 4
示例代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> myVector;
int main(){
int n, input;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> input;
myVector.push_back(input);
}
sort(myVector.begin(), myVector.end());
for(vector<int>::iterator iter = myVector.begin(); iter != myVector.end(); iter++){
cout << *iter << " ";
}
cout << endl;
myVector.clear();
}
return 0;
}
2、题目描述:用一维数组存储学号和成绩,然后,按成绩排序输出。【清华大学】
- 输入格式:输入第一行包括一个整数N(1<=N<=100),代表学生的个数。接下来的N行每行包括两个整数p和q,分别代表每个学生的学号和成绩。
- 输出格式:按照学生的成绩从小到大进行排序,并将排序后的学生信息打印出来。如果学生的成绩相同,则按照学号的大小进行从小到大排序。
- 样例输入:
- 3
- 1 90
- 2 87
- 3 92
- 样例输出:
- 2 87
- 1 90
- 3 92
示例代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Student{
int number;
int score;
Student(int n, int s):number(n), score(s){};
bool operator<(const Student &stu);
};
vector<Student> stuVector;
bool Student::operator<(const Student &stu){
if(score < stu.score){
return true;
}else if(score == stu.score){
return number < stu.number;
}else{
return false;
}
}
int main(){
int n, number, score;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> number >> score;
Student stu(number, score);
stuVector.push_back(stu);
}
sort(stuVector.begin(), stuVector.end());
for(vector<Student>::iterator iter = stuVector.begin(); iter != stuVector.end(); iter++){
cout << (*iter).number << " " << iter->score << endl;
}
stuVector.clear();
}
return 0;
}
3、题目描述:输入任意(用户,成绩)序列,可以获得成绩从高到低或从低到高的排列,相同成绩都按先录入排列在前的规则处理。【清华大学】
- 输入格式:输入多行,先输入要排序的人的个数,然后输入排序方法0(降序)或者1(升序)再分别输入他们的名字和成绩,以一个空格隔开
- 输出格式:按照指定方式输出名字和成绩,名字和成绩之间以一个空格隔开
- 样例输入:
- 3
- 0
- fang 90
- yang 50
- ning 70
- 样例输出:
- fang 90
- ning 70
- yang 50
示例代码:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
struct Student{
string name;
int score;
int order;
Student(string n, int s, int o):name(n), score(s), order(o){};
};
vector<Student> stuVector;
bool CompareAsc(const Student &stuA, const Student &stuB){
if(stuA.score != stuB.score){
return stuA.score < stuB.score;
}else{
return stuA.order < stuB.order;
}
}
bool CompareDesc(const Student &stuA, const Student &stuB){
if(stuA.score != stuB.score){
return stuA.score > stuB.score;
}else{
return stuA.order < stuB.order;
}
}
int main(){
int number, orderStyle, score;
string name;
while(cin >> number){
cin >> orderStyle;
int count = 0;
for(int i = 0; i < number; i++){
cin >> name >> score;
count++;
Student stu(name, score, count);
stuVector.push_back(stu);
}
if(orderStyle == 0){
sort(stuVector.begin(), stuVector.end(), CompareDesc);
}else{
sort(stuVector.begin(), stuVector.end(), CompareAsc);
}
for(vector<Student>::iterator iter = stuVector.begin(); iter != stuVector.end(); iter++){
cout << iter->name << " " << iter->score << endl;
}
stuVector.clear();
}
return 0;
}
4、题目描述:输入一系列整数,将其中最大的数挑出(如果有多个,则挑出一个即可),并将剩下的数进行排序,如果无剩余的数,则输出-1。【华中科技大学】
- 输入格式:输入第一行包括1个整数N,1<=N<=1000,代表输入数据的个数。接下来的一行有N个整数。
- 输出格式:可能有多组测试数据,对于每组数据,第一行输出一个整数,代表N个整数中的最大值,并将此值从数组中去除,将剩下的数进行排序。第二行将排序的结果输出。
- 样例输入:
- 4
- 1 3 4 2
- 样例输出:
- 4
- 1 2 3
示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> myVector;
int main(){
int n, inputNumber;
while(cin >> n){
if(n == 1){
cin >> inputNumber;
cout << inputNumber << endl << -1 << endl;
}else{
for(int i = 0; i < n; i++){
cin >> inputNumber;
myVector.push_back(inputNumber);
}
sort(myVector.begin(), myVector.end());
cout << myVector.back() << endl;
for(vector<int>::iterator iter = myVector.begin(); iter != myVector.end() - 1; iter++){
cout << *iter << " ";
}
cout << endl;
myVector.clear();
}
}
return 0;
}
5、题目描述:输入10个整数,彼此以空格分隔。重新排序以后输出(也按空格分隔),要求: 1.先输出其中的奇数,并按从大到小排列; 2.然后输出其中的偶数,并按从小到大排列。【北京大学】
- 输入格式:任意排序的10个整数(0~100),彼此以空格分隔。
- 输出格式:可能有多组测试数据,对于每组数据,按照要求排序后输出,由空格分隔。1. 测试数据可能有很多组,请使用while(cin>>a[0]>>a[1]>>...>>a[9])类似的做法来实现;2. 输入数据随机,有可能相等。
- 样例输入:
- 4 7 3 13 11 12 0 47 34 98
- 样例输出:
- 47 13 11 7 3 0 4 12 34 98
示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> oddVector;
vector<int> evenVector;
bool CompareAsc(const int &a, const int &b){
return a < b;
}
bool CompareDesc(const int &a, const int &b){
return a > b;
}
void Print(vector<int> v){
for(int i = 0; i < v.size(); i++){
cout << v[i] << " ";
}
}
int main(){
int inputNumber;
while(cin >> inputNumber){
if(inputNumber % 2 == 0){
evenVector.push_back(inputNumber);
}else{
oddVector.push_back(inputNumber);
}
for(int i = 0; i < 9; i++){
cin >> inputNumber;
if(inputNumber % 2 == 0){
evenVector.push_back(inputNumber);
}else{
oddVector.push_back(inputNumber);
}
}
if(oddVector.size() != 0){
sort(oddVector.begin(), oddVector.end(), CompareDesc);
Print(oddVector);
oddVector.clear();
}
if(evenVector.size() != 0){
sort(evenVector.begin(), evenVector.end(), CompareAsc);
Print(evenVector);
evenVector.clear();
}
cout << endl;
}
return 0;
}
6、题目描述:N只小白鼠(1 <= N <= 100),每只鼠头上戴着一顶有颜色的帽子。现在称出每只白鼠的重量,要求按照白鼠重量从大到小的顺序输出它们头上帽子的颜色。帽子的颜色用“red”,“blue”等字符串来表示。不同的小白鼠可以戴相同颜色的帽子。白鼠的重量用整数表示。【北京大学】
- 输入格式:多案例输入,每个案例的输入第一行为一个整数N,表示小白鼠的数目。下面有N行,每行是一只白鼠的信息。第一个为不大于100的正整数,表示白鼠的重量,;第二个为字符串,表示白鼠的帽子颜色,字符串长度不超过10个字符。注意:白鼠的重量各不相同。
- 输出格式:每个案例按照白鼠的重量从大到小的顺序输出白鼠的帽子颜色。
- 样例输入:
- 3
- 30 red
- 50 blue
- 40 green
- 样例输出:
- blue
- green
- red
示例代码:
#include <iostream>
#include <map>
#include <string>
using namespace std;
map<int, string> myMap;
int main(){
int n, weight;
string color;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> weight >> color;
myMap[weight] = color;
}
for(map<int, string>::reverse_iterator iter = myMap.rbegin(); iter != myMap.rend(); iter++){
cout << iter->second << endl;
}
myMap.clear();
}
return 0;
}
7、题目描述:按要求,给国家进行排名。【浙江大学】
- 输入格式:有多组数据。第一行给出国家数N,要求排名的国家数M,国家号从0到N-1。第二行开始的N行给定国家或地区的奥运金牌数,奖牌数,人口数(百万)。接下来一行给出M个国家号。
- 输出格式:排序有4种方式: 金牌总数 奖牌总数 金牌人口比例 奖牌人口比例 。对每个国家给出最佳排名排名方式 和 最终排名。格式为: 排名:排名方式。如果有相同的最终排名,则输出排名方式最小的那种排名,对于排名方式,金牌总数 < 奖牌总数 < 金牌人口比例 < 奖牌人口比例 。如果有并列排名的情况,即如果出现金牌总数为 100,90,90,80.则排名为1,2,2,4。每组数据后加一个空行。
- 样例输入:
- 4 4
- 4 8 1
- 6 6 2
- 4 8 2
- 2 12 4
- 0 1 2 3
- 4 2
- 8 10 1
- 8 11 2
- 8 12 3
- 8 13 4
- 0 3
- 样例输出:
- 1:3
- 1:1
- 2:1
- 1:2
- 1:1
- 1:1
示例代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MIN_VALUE = 99999999;
struct Country{
int gold; //金牌总数
int total; //奖牌总数
int people; //人口数
int countryNo; //国家号
double goldPerPerson; //金牌人口比例
double totalPerPerson; //奖牌人口比例
int type1; //金牌总数排名
int type2; //奖牌总数排名
int type3; //金牌人口比例排名
int type4; //奖牌人口比例排名
Country(int g, int t, int p, int c, double gp, double tp):
gold(g), total(t), people(p), countryNo(c), goldPerPerson(gp), totalPerPerson(tp){};
};
vector<Country> cVector;
vector<Country> result;
bool CompareGoldNumber(const Country &c1, const Country &c2){
return c1.gold > c2.gold;
}
bool CompareTotalMedal(const Country &c1, const Country &c2){
return c1.total > c2.total;
}
bool CompareGoldPerPerson(const Country &c1, const Country &c2){
return c1.goldPerPerson > c2.goldPerPerson;
}
bool CompareMetalPerPerson(const Country &c1, const Country &c2){
return c1.totalPerPerson > c2.totalPerPerson;
}
bool ComparecountryNo(const Country &c1, const Country &c2){
return c1.countryNo < c2.countryNo;
}
int main(){
int N, M;
while(cin >> N >> M){
int gold, total, people;
for(int i = 0; i < N; i++){
cin >> gold >> total >> people;
double totalPerOrder = total * 1.0 / people;
double goldPerOrder = gold * 1.0 / people;
Country country(gold, total, people, i, goldPerOrder, totalPerOrder);
cVector.push_back(country);
}
int index;
for(int i = 0; i < M; i++){
cin >> index;
for(int j = 0; j < cVector.size(); j++){
if(cVector[j].countryNo == index){
result.push_back(cVector[j]);
break;
}
}
}
sort(result.begin(), result.end(), CompareGoldNumber);
result[0].type1 = 1;
for(int i = 1; i < result.size(); i++){
if(result[i].gold == result[i - 1].gold){
result[i].type1 = result[i - 1].type1;
}else{
int count = 1, tmp = i;
while(tmp - 2 >= 0 && result[tmp - 2].gold == result[tmp - 1].gold){
tmp--;
count++;
}
result[i].type1 = result[i - 1].type1 + count;
}
}
sort(result.begin(), result.end(), CompareTotalMedal);
result[0].type2 = 1;
for(int i = 1; i < result.size(); i++){
if(result[i].total == result[i - 1].total){
result[i].type2 = result[i - 1].type2;
}else{
int count = 1, tmp = i;
while(tmp - 2 >= 0 && result[tmp - 2].total == result[tmp - 1].total){
tmp--;
count++;
}
result[i].type2 = result[i - 1].type2 + count;
}
}
sort(result.begin(), result.end(), CompareGoldPerPerson);
result[0].type3 = 1;
for(int i = 1; i < result.size(); i++){
if(result[i].goldPerPerson == result[i - 1].goldPerPerson){
result[i].type3 = result[i - 1].type3;
}else{
int count = 1, tmp = i;
while(tmp - 2 >= 0 && result[tmp - 2].goldPerPerson == result[tmp - 1].goldPerPerson){
tmp--;
count++;
}
result[i].type3 = result[i - 1].type3 + count;
}
}
sort(result.begin(), result.end(), CompareMetalPerPerson);
result[0].type4 = 1;
for(int i = 1; i < result.size(); i++){
if(result[i].totalPerPerson == result[i - 1].totalPerPerson){
result[i].type4 = result[i - 1].type4;
}else{
int count = 1, tmp = i;
while(tmp - 2 >= 0 && result[tmp - 2].totalPerPerson == result[tmp - 1].totalPerPerson){
tmp--;
count++;
}
result[i].type4 = result[i - 1].type4 + count;
}
}
sort(result.begin(), result.end(), ComparecountryNo);
for(int i = 0; i < result.size(); i++){
int min = MIN_VALUE, resultType;
if(result[i].type1 < min){
resultType = 1;
min = result[i].type1;
}
if(result[i].type2 < min){
resultType = 2;
min = result[i].type2;
}
if(result[i].type3 < min){
resultType = 3;
min = result[i].type3;
}
if(result[i].type4 < min){
resultType = 4;
min = result[i].type4;
}
cout << min << ":" << resultType << endl;
}
cout << endl;
cVector.clear();
result.clear();
}
return 0;
}
8、题目描述:输入一个数n,然后输入n个数值各不相同,再输入一个值x,输出这个值在这个数组中的下标(从0开始,若不在数组中则输出-1)。【浙江大学】
- 输入格式:测试数据有多组,输入n(1<=n<=200),接着输入n个数,然后输入x。
- 输出格式:对于每组输入,请输出结果。
- 样例输入:
- 2
- 1 3
- 0
- 样例输出:
- -1
示例代码:
#include <iostream>
#include <vector>
using namespace std;
vector<int> myVector;
int main(){
int n;
while(cin >> n){
int number, x;
for(int i = 0; i < n; i++){
cin >> number;
myVector.push_back(number);
}
cin >> x;
bool flag = true;
for(int i = 0; i < myVector.size(); i++){
if(myVector[i] == x){
flag = false;
cout << i << endl;
break;
}
}
if(flag){
cout << "-1" << endl;
}
myVector.clear();
}
return 0;
}
9、题目描述:输入数组长度 n 输入数组 a[1...n] 输入查找个数m 输入查找数字b[1...m] 输出 YES or NO 查找有则YES 否则NO 。【北京邮电大学】
- 输入格式:输入有多组数据。每组输入n,然后输入n个整数,再输入m,然后再输入m个整数(1<=m,n<=100)。
- 输出格式:如果在n个数组中输出YES否则输出NO。
- 样例输入:
- 5
- 1 5 2 4 3
- 3
- 2 5 6
- 样例输出:
- YES
- YES
- NO
示例代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> myVector;
int main(){
int m, n;
while(cin >> n){
int number;
for(int i = 0; i < n; i++){
cin >> number;
myVector.push_back(number);
}
sort(myVector.begin(), myVector.end());
cin >> m;
for(int i = 0; i < m; i++){
cin >> number;
string result = "NO";
for(int j = 0; j < myVector.size(); j++){
if(myVector[j] == number){
result = "YES";
break;
}else if(myVector[j] > number){
break;
}
}
for(int i = 0; i < result.size(); i++){
cout << result[i];
}
cout << endl;
}
myVector.clear();
}
return 0;
}
10、题目描述:第一行输入一个数n,1 <= n <= 1000,下面输入n行数据,每一行有两个数,分别是x y。输出一组x y,该组数据是所有数据中x最小,且在x相等的情况下y最小的。 【北京邮电大学】
- 输入格式:输入有多组数据。每组输入n,然后输入n个整数对。
- 输出格式:输出最小的整数对。
- 样例输入:
- 5
- 3 3
- 2 2
- 5 5
- 2 1
- 3 6
- 样例输出:
- 2 1
示例代码:
#include <iostream>
using namespace std;
const int MAX_N = -(1 << 31) - 1;
int main(){
int n;
int x, y;
while(cin >> n){
int min_x = MAX_N, min_y = MAX_N;
for(int i = 0; i < n; i++){
cin >> x >> y;
if(x < min_x){
min_x = x;
min_y = y;
}else if(x == min_x && y < min_y){
min_y = y;
}
}
cout << min_x << " " << min_y << endl;
}
return 0;
}
11、题目描述:在一个整数数组上,对于下标为i的整数,如果它大于所有它相邻的整数, 或者小于所有它相邻的整数,则称为该整数为一个极值点,极值点的下标就是i。【北京大学】
- 输入格式:第一行是此数组的元素个数k(4<k<80),第二行是k个整数,每两个整数之间用空格分隔。
- 输出格式:每个案例输出为n行:每行对应于相应数组的所有极值点下标值,下标值之间用空格分隔。
- 样例输入:
- 10
- 10 12 12 11 11 12 23 24 12 12
- 15
- 12 12 122 112 222 211 222 221 76 36 31 234 256 76 76
- 15
- 12 14 122 112 222 222 222 221 76 36 31 234 256 76 73
- 样例输出:
- 0 7
- 2 3 4 5 6 10 12
- 0 2 3 10 12 14
示例代码:
#include <iostream>
#include <vector>
using namespace std;
vector<int> myVector;
vector<int> result;
int main(){
int n, inputNumber;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> inputNumber;
myVector.push_back(inputNumber);
}
for(int i = 0; i < myVector.size(); i++){
if(i == 0){
if(myVector[i] != myVector[i + 1]){
result.push_back(i);
}
}else{
if(i != myVector.size() - 1){
if((myVector[i] > myVector[i - 1] && myVector[i] > myVector[i + 1]) ||
(myVector[i] < myVector[i - 1] && myVector[i] < myVector[i + 1])){
result.push_back(i);
}
}else{
if(myVector[i] != myVector[i - 1]){
result.push_back(i);
}
}
}
}
for(int i = 0; i < result.size(); i++){
cout << result[i] << " ";
}
cout << endl;
myVector.clear();
result.clear();
}
return 0;
}
12、题目描述:对给定的一个字符串,找出有重复的字符,并给出其位置,如:abcaaAB12ab12 输出:a,1;a,4;a,5;a,10,b,2;b,11,1,8;1,12, 2,9;2,13。【华中科技大学】
- 输入格式:输入包括一个由字母和数字组成的字符串,其长度不超过100。
- 输出格式:可能有多组测试数据,对于每组数据,按照样例输出的格式将字符出现的位置标出。1、下标从0开始。2、相同的字母在一行表示出其出现过的位置。
- 样例输入:
- abcaaAB12ab12
- 样例输出:
- a:0,a:3,a:4,a:9
- b:1,b:10
- 1:7,1:11
- 2:8,2:12
示例代码:
#include <map>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
map<char, vector<int> > myMap;
vector<char> orderVector;
int main(){
string str;
while(cin >> str){
for(int i = 0; i < str.size(); i++){
if(myMap.find(str[i]) == myMap.end()){
orderVector.push_back(str[i]);
vector<int> v;
v.push_back(i);
myMap[str[i]] = v;
}else{
vector<int> v = myMap[str[i]];
v.push_back(i);
myMap[str[i]] = v;
}
}
for(int j = 0; j < orderVector.size(); j++){
vector<int> v;
for(map<char, vector<int> >::iterator iter = myMap.begin(); iter != myMap.end(); iter++){
if(iter->first == orderVector[j]){
v = iter->second;
break;
}
}
if(v.size() > 1){
int i = 0;
for(i = 0; i < v.size() - 1; i++){
cout << orderVector[j] << ":" << v[i] << ",";
}
cout << orderVector[j] << ":" << v[i] << endl;
}
}
myMap.clear();
orderVector.clear();
}
return 0;
}
参考文献:
[1]杨泽邦、赵霖. 计算机考研——机试指南(第2版). [M]北京:电子工业出版社,2019.11;