《算法笔记》笔记之笔记 - 4、算法初步(1) - 4.排序题与sort函数的应用

16 篇文章 0 订阅
16 篇文章 0 订阅

4.1.4 排序题与sort函数的应用

sort()函数是用来排序的函数,属于C++标准模板库。它根据具体情形使用不同的排序算法,效率较高。还可以规避经典快速排序中可能出现的会导致实际复杂度退化到 O ( n 2 ) O(n^2) O(n2)的极端情况。

  1. 如何使用sort排序

sort的使用必须先添加头文件#include <algorithm>using namespace std;,格式如下:

sort(首元素地址, 尾元素地址的下一个地址(, 比较函数));

如果不给出比较函数,sort函数会默认对序列进行递增排序。

由于对序列进行排序,要求序列的元素一定要具有可比性。但是对于结构体等,这种本身并没有大小关系的,就需要我们人为制定比较规则了。这也就是第三个可选参数,比较函数的意义。

  1. 如何实现比较函数cmp

(1)基本数据类型数组的排序

// 可以将int改成double、char等
bool cmp(int a, int b){
    // 这里表示从大到小排列,可以形象地看作左大又小
    return a > b;
    // // 表示从小到大排列,可以形象地看作左小右大
    // return a < b;
}

(2)结构体数组的排序

假设定义了如下结构体:

struct node{
    char name[10];
    // string name;
    int x, y;
}ssd[10];

如果想将ssd数组按照x从大到小排序(即进行一级排序),可以这么写:

bool cmp(node a, node b){
    return a.x > b.x;
}

如果想先按照x从大到小排序,当x相等的情况下,再将name按照字典序从小到大排序(即进行二级排序),则cmp函数可以这么写:

bool cmp(node a, node b){
    if(a.x != b.x){
        return a.x > b.x;
    }else{
        return strcmp(a.name, b.name) < 0;
        // // 如果使用string的话,比较更方便
        // return a.name < b.name;
    }
}

strcmpstring.h头文件中所含的函数,用来比较两个char型数组的字典序大小的。可以查看前面2.5.6节回顾用法。

(3)容器的排序

在STL标准容器中,只有vector、string、deque是可以使用sort的。注意,使用这些容器都要引入相关的头文件,比如vector要引入头文件#include <vector>,string要引入头文件#include <string>等,两者同时还要加上using namespace std;。提醒一下,string是C++中的容器,而C语言中也有一个string的头文件,但是两者完全不一样。C语言中string的引入方法是#include <cstring>或者#include <string.h>

// 因为vector中的元素为int型,因此仍然是int的比较
// 对于string也只需要将int改成string即可
bool cmp(int a, int b){
    // 从大到小排列
    return a > b;
}

对于字符串,还可以按照长度来进行排序:

bool cmp(string a, string b){
    // 按照字符串的长度从小到大排序
    return a.length() < b.length()
}
【PAT A1025】PAT Ranking

题目描述:

Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Zhejiang University. Each test is supposed to run simultaneously in several places, and the ranklists will be merged immediately after the test. Now it is your job to write a program to correctly merge all the ranklists and generate the final rank.

输入格式:

Each input file contains one test case. For each case, the first line contains a positive number N ( ≤ 100 ) N(\leq 100) N(100), the number of test locations. Then N N N ranklists follow, each starts with a line containing a positive integer K ( ≤ 300 ) K(\leq 300) K(300), the number of testees, and then K K K lines containing the registration number (a 13-digit number) and the total score of each testee. All the numbers in a line are separated by a space.

输出格式:

For each test case, first print in one line the total number of testees. Then print the final ranklist in the following format:

registration_number final_rank location_number local_rank

The locations are numbered from 1 to N N N. The output must be sorted in nondecreasing order of the final ranks. The testees with the same score must have the same rank, and the output must be sorted in nondecreasing order of their registration numbers.

输入样例:

2

5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85

输出样例:

9
1234567890005 1 1 1
1234567890014 1 2 1
1234567890001 3 1 2
1234567890003 3 1 2
1234567890004 5 1 4
1234567890012 5 2 2
1234567890002 7 1 5
1234567890013 8 2 3
1234567890011 9 2 4

题意:

N N N个考场,每个考场有若干个考生。给出每个考生的准考证号和分数,将考生按照分数从高到低进行排序,若分数相同则根据准考证号从小到大排序。然后按照顺序输出所有考生的准考证号、排名、考场号和考场中的排名。

思路:

使用结构体存储考生的信息,然后定义一个比较函数cmp;

循环遍历每一个考场并读入考生数据的时候,先将这个考场的考生根据分数进行排序并将排名记录下来;

遍历完所有考场的考生并读入数据后,再将所有考生按照要求进行排序;

最后输出要求的考生信息。

注意:题目要求分数相同时,排名相同。若有两个考生都考了100分,一个考了98分,则两个考生并列第一,第三个考生为第三名。这里要注意排名的情况。

参考代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

// 定义结构体存储考生信息
struct Student{
    // 准考证号,13位数,保险起见大一点
    char id[15];
    // 分数
    int score;
    // 考场号
    int location_number;
    // 考场内排名
    int local_rank;
}stu[30010];	// 考生总人数要小于等于300*100=30000,定义大一点

bool cmp(Student a, Student b){
    if(a.score != b.score){
        // 分数不同,按照分数从大到小排列
        return a.score > b.score;
    }else{
        // 分数相同,按照准考证号的字典序从小到大排列
        return strcmp(a.id, b.id) < 0;
    }
}

int main(){

    // n记录考场数;k记录每一个考场的人数;num记录总人数
    int n, k, num=0;
    scanf("%d", &n);

    for(int i=0; i<n; i++){
        scanf("%d", &k);
        // 循环遍历一个考场内的考生
        for(int j=0; j<k; j++){
            // 读入考生准考证号和分数
            scanf("%s %d", stu[num].id, &stu[num].score);
            // 记录每一个考生的考场号
            stu[num].location_number = i+1;
            // 总人数+1
            num++;
        }

        // 将一个考场内的考生进行排序
        sort(stu+num-k, stu+num, cmp);

        // 将第一个考生的考场排名定为1
        stu[num-k].local_rank = 1;
        // 循环遍历这个考场的考生
        for(int j=1; j<k; j++){
            // 如果后一个考生的分数跟前一个相同
            if(stu[num-k+j-1].score == stu[num-k+j].score){
                // 将前一个考生的排名赋值给后一个考生
                stu[num-k+j].local_rank = stu[num-k+j-1].local_rank;
            }else{
                // 否则考生排名为当前已经排好名的考场人数
                stu[num-k+j].local_rank = j + 1;
            }
        }
    }
    // 输出考生的总人数
    printf("%d\n", num);
    // 将所有考生进行排序
    sort(stu, stu+num, cmp);

    // 将第一个考生的排名定为1
    int rank=1;
    // 循环遍历所有考生
    for(int i=0; i<num; i++){
        // 如果后一个考生的分数比前一个考生的分数高
        if(i>0 && stu[i-1].score > stu[i].score){
            // 排名为当前已经排好名的考生人数
            // 否则排名相同
            rank = i + 1;
        }
        // 直接输出考生的信息
        printf("%s %d %d %d\n", stu[i].id, rank, stu[i].location_number, stu[i].local_rank);
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值