【冒泡排序】每趟依次两两对比元素,并且每趟会确定最大/小元素的最终位置。
#include <iostream>
#include <vector>
using namespace std;
void swap(int &a, int &b);
int main()
{
int n;
cin >> n;
vector<int> v(n); //大小为n的数组
for ( int i=0; i<n; i++ )
cin >> v[i];
//冒泡排序-->从小到大排列
for ( int i=0; i<n-1; i++ ){
//共比较n-1趟
for ( int j=1; j<n; j++ ){
if ( v[j-1]>v[j] )
swap(v[j-1],v[j]);
}
}
cout << v[0];
for ( int i=1; i<n; i++ )
cout << " " << v[i];
return 0;
}
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
实现核心其实就是交换两个数。
【简单选择排序】序列分为有序部分和待排序部分,每趟从待排序部分找出最小/大值增加到有序部分的末尾。
#include <iostream>
#include <vector>
using namespace std;
void swap(int &a, int &b); //交换两个数
int find_minindex(int k, int n, vector<int> a); //找到数组a的最小值下标,k为待排序起始下标,n为数组长度
int main()
{
int n;
cin >> n;
vector<int> v(n); //大小为n的数组
for ( int i=0; i<n; i++ )
cin >> v[i];
//简单选择排序-->从小到大排列
for ( int i=0; i<n; i++ ){
//共交换n趟
int min = find_minindex(i,n,v);
cout << v[min] << endl;
swap(v[i],v[min]);
}
//0 2 4 1 2 --> 1 0 2 2 4
cout << v[0];
for ( int i=1; i<n; i++ )
cout << " " << v[i];
return 0;
}
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
int find_minindex(int k, int n, vector<int> a)
{
int min = k;
for ( int i=k+1; i<n; i++ ){
//共比较k-1趟
if ( a[i]<a[min] )
min = i;
}
return min;
}
实现核心比冒泡排序多了个找最小/大值下标,整合如下
void selectSort(int k, int n, vector<int> a)
{
for ( int i=0; i<n; i++ ){
//进行n趟操作
int min = k;
for ( int j=i+1; j<n; j++ ){
//选出[i,n-1]中的最小元素,下标为min
if ( a[i]<a[min] )
min = i;
}
swap(a[i],a[min]);
}
}
【直接插入排序】序列仍分为有序和待排序两个部分,但这次是将待排序列中的元素依次插入到有序序列的合适位置中去。
void insertSort(int n, vector<int>a )
{
for ( int i=1; i<n; i++ ){
//共n-1趟操作
int tmp = a[i], j = i;
//注意由于后面要移动数据,所以这里先把待插入元素存在tmp中,并且后面的比较与插入操作都要用tmp
while ( j>0 && a[j-1]>tmp ){
//从后向前比较
a[j] = a[j-1]; //把v[j-1]后移至v[j]
j--;
}
a[j] = tmp; //最终插入的位置为j
}
}
#include <algorithm>
using namespace std;
sort(begin,end_next,cmp);
【sort函数】参数分别为首元素地址(必填),尾元素地址的下一个地址(必填),比较函数(非必填)(默认递增排序)。
sort函数默认递增排序,即相当于
bool cmp(ElemType a, ElemType b){
return a < b;
}
bool cmp(ElemType a, ElemType b){
return a > b;
}
可以理解为当a>b时把a放在b前面
此时,cmp函数传入的参数类型改为结构体类型。
定义结构体如下:
struct node{
int x, y;
}ssd[10];
可进行一级排序:如将数组ssd按照x从大到小排序
bool cmp(node a, node b){
return a.x > b.x;
}
也可以进行二级排序:如将数组ssd先按照x从大到小排序,但当x相等的情况下,按照y的大小从小到大来排序
bool cmp(node a, node b){
if(a.x != b.x) return a.x > b.x;
else return a.y < b.y;
}
在STL标准容器中,只有vector、string、deque是可以使用sort的。(set、map容器中元素本身就有序,不允许使用sort排序)。
*注意:对vector中元素进行排序时,cmp参数类型与vector中元素类型一致即可,如cmp(int a, int b)即可。
原题目:1025 PAT Ranking (25 分)
题目大意: 有N个考场(1-N),接着给出每个考场的考生数量K及每个考生的注册号和成绩。要求:①计算考生总数;②生成总的成绩排行榜,成绩相同时排名相同且按注册号非递减排序。
分析: ①定义结构体类型数组存放考生注册号、成绩、考场号、最终排名以及考场内排名。
②sort函数:先对每个考场的考生进行排名(在输入时完成),而后复制到总数组,再进行总的排名。
③cmp函数:分数不同时,按分数递减排序;分数相同时,按注册号递增排序。
④排名的计算:排序后,设置第一个元素的排名为‘1’,而后的元素,若与前一个元素成绩相同则排名也相同,否则排名为数组下标(从0开始时)+1(错误点)。
词汇: nondecreasing order非递减次序
其他词汇: simultaneously同时;ranklist排行榜;test location测试点;testee考生;registration number注册号
#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
using namespace std;
struct testee{
long long int no; //注册号
//char no[14];
int score, finr, loc, locr; //成绩,最终排名,考场号,考场内排名
};
bool cmp(testee a, testee b){
if ( a.score!=b.score )
return a.score>b.score; //先按成绩递减排序
else return a.no<b.no; //再按注册号递增排序
//else return strcmp(a.no, b.no)<0;
/*//上述可写成:
return a.score!=b.score ? a.score>b.score : a.no
}
int main()
{
int n, k;
cin >> n;
vector<testee> fin; //记录总情况
for ( int i=1; i<=n; i++ ){
//n个考场
cin >> k;
vector<testee> v(k); //记录每个考场的情况
for ( int j=0; j<k; j++ ){
v[j].loc = i; //考场号为i
cin >> v[j].no >> v[j].score;
//scanf("%s %d", &v[j].no, &v[j].score);
}
sort(v.begin(), v.end(), cmp); //考场内排序
v[0].locr = 1; //排序后设置第一个排名为‘1’
fin.push_back(v[0]); //将排名好的压入最终数组
for ( int j=1; j<k; j++ ){
//计算考场内排名
if ( v[j].score==v[j-1].score )
v[j].locr = v[j-1].locr;
else v[j].locr = j+1;
/*//上述可写成:
v[j].score = (v[j].score==v[j-1].score) ? v[j-1].locr : j+1;*/
fin.push_back(v[j]); //将排名好的立即压入最终数组
}
}
sort(fin.begin(), fin.end(), cmp); //总排序
fin[0].finr = 1;
for ( int i=1; i<fin.size(); i++ ){
//总排名
if ( fin[i].score==fin[i-1].score )
fin[i].finr = fin[i-1].finr;
else fin[i].finr = i+1;
/*//上述可写成:
fin[i].score = (fin[i].score==fin[i-1].score) ? fin[i-1].finr : i+1;*/
}
cout << fin.size() << endl;
for ( int i=0; i<fin.size(); i++ )
//printf("%s %d %d %d\n", fin[i].no, fin[i].finr, fin[i].loc, fin[i].locr);
printf("%013ld %d %d %d\n", fin[i].no, fin[i].finr, fin[i].loc, fin[i].locr);
return 0;
}
用vector容器时,可以将整个结构体类型元素压入push_back到另一个vector容器中,不需要对每个结构体的内容逐项“复制”。
使用vector的size()即可,不需另设变量cnt来统计。
【strcmp函数】需要头文件string.h(不同于string);用来比较两个char型数组的字典序大小。需要注意的是,返回值不一定是+1或-1(与编译器有关),故判断用>0或<0为好。
错误点
1.分数不同时,第i个考生就是第i名,而不是上一排名+1。
2.关于学生注册号的存取:
(1)109以内都可以用int
(2)1016以内可以用long long
(3)但是在存储类似注册号这样的编号时,要防止编号以0开头,若用数字类型变量存储则会丢失编号开头的’0‘位。
解决办法:①仍用long long型,但输出的时候要用 %013ld。
②用char型数组或者string类型:
char型数组
·头文件:string.h(区别于头文件string)
·读入字符串时,%s识别空格作为字符串的结尾
·用strcmp比较大小
string类型
`头文件:string(还需要using namespace std;)
·一般用cin/cout,除非str.c_str()才可用printf
·可以直接比较大小