NUIST OJ 1364 [2017 江苏科技大学 程序设计竞赛]D.重复成绩统计(改编) 【STL-map】

来源:互联网 发布:中国贸易顺差历年数据 编辑:程序博客网 时间:2024/04/28 07:36

NUIST OJ 1364 [2017 江苏科技大学 程序设计竞赛]D.重复成绩统计(改编) 【STL-map】

  • NUIST OJ 1364 2017 江苏科技大学 程序设计竞赛D重复成绩统计改编 STL-map
    • 题目
    • map
      • map使用
      • map插入
      • map查找
      • map的清空与判断是否为空
      • map的删除
      • map内排序
    • 解题代码
    • 随便说说
    • 再来一个随便说说

题目

题目描述

上海闵行膜法学院刚刚结束了高等膜法期中考试,现在有 N ( 0 < N < 1000000) 个学生的成绩需要统计,管理教学的长者们想要知道成绩的总体分布情况,请将不同分数的成绩和人数统计好并分别输出。

输入描述

有多组测试数据,每组测试数据占若干行。
在第 1 行中,有一个数字 N。
在第 2 到第 N + 1 行中,每行一个数字,代表这是一个学生的成绩。
所有数据保证在 32 位有符号整数范围内。

输出描述

每一行的输出格式为:成绩 取得这个成绩的人数。
注意:成绩和取得这个成绩的人数中间有一个空格! 同时,输出的时候。请按成绩的大小从低到高输出
由于数据量较大,请尽量使用时间复杂度较低的排序算法。

样例输入

5
45
45
45
60
60
6
100
60
100
100
50
60

样例输出

45 3
60 2
50 1
60 2
100 3

若是没有接触过STL-map,则很直接会想到用数组或是顺序栈来储存数据,利用 algorithm 中的sort()进行排序。若是遍历到了则相应数据+1,没有遍历到则插入。或者是使用链栈的结构存储。这样就不需要搬动或是交换数据,但是其需要两个值域分别表示成绩与人次,且查找插入也比较麻烦。
由此,有没有一种高效简洁的结构来存储这样一对一的数据呢。这就是STL中的map

map

map是用来存放<key, value>键值对的数据结构,可以很方便快速的根据key查到相应的value。其中,key是唯一的。
其中key和value可以根据需要来使用。也可以是自定义的结构体或类,甚至可以嵌套另一个map。例如,需要key值为姓名,value为电话号码,那么描述函数就可以写成

map<string,int>info;

这样就声明了一个key为string类型,value为int类型的map容器。
上面说到key值是唯一的,那么即不可能同时满足
info[MFS]==1;
info[MFS]==2;
若存在同时创建了两个key相同的情况,前一个即被覆盖。

map使用

使用map需包含map类所在的头文件:

#include <map>

描述函数

Template<class T1, class T2>

map插入

map插入有三种方式
1.用insert方法插入pair对象:

info.insert(pair<string, int>("MSF", 1));

2.用insert方法插入value_type对象:

info.insert(map<string, int>::value_type ("MSF", 1));

3.用数组方式插入值:

info["MSF"] = 1;info["JZM"] = 2;......

第三种方式存在性能问题。插入”JZM”时,先在info中查找key为”JZM”的元素,没发现,然后将一个新的元素插入info,key是”JZM”,value为空,插入完成后,将value赋为需要的值。 该方法会将每个value都赋为缺省值,然后再赋为需要的值,如果元素是复杂的类或者结构体,则进行了许多无意义的操作,较为浪费时间。而前两种方法可以避免这个问题。

map查找

可以使用find()和count()函数来发现一个键是否存在。

对于find()函数,先介绍begin()和end()两个成员函数,分别代表map实例对象中第一个元素和最后一个元素其后的一个位置,函数返回类型是iterator.

map<int, string>::iterator iter;iter = info.find("JZM");if(iter != info.end()){…………/*find*/}Else{…………/*can not find*/}

iter是一个iterator类对象。这里的iterator是在template class map中声明的一个类,所以需要用

map<int, string>::iterator iter

来声明一个迭代器iter。

其次介绍count()函数。用count函数来判定关键字是否出现,但其无法定位数据出现位置。由于map一对一的映射关系,就决定了count函数的返回值只有两个,要么是0,要么是1。

map的清空与判断是否为空

清空map中的数据可以用clear()函数,
判定map中是否有数据可以用empty()函数,其返回值类型为bool

map的删除

1.如果要删除”JZM”,用迭代器删除

map<int, string>::iterator iter;iter = info.find("JZM");info.erase(iter);

2.如果要删除“JZM,用关键字删除

int n = info.erase("JZM");//如果删除了会返回1,否则返回0

3.用迭代器,成片的删除

info.earse(info.begin()+m, info.end()-n);

注:删除区间是一个前闭后开的集合

map内排序

此处回顾一下map的定义

template < class Key, class T, class Compare = less<Key>,             class Allocator = allocator<pair<const Key,T> > > class map;  

其一共有四个参数,第四个是 Allocator,用来定义存储分配模型。
而第三个参数: class Compare = less<key, value>
map这里指定less作为其默认比较函数,其实质是对operator()操作符的重载。所以如果不自己指定Compare(),map中键值对就会按照Key的less顺序进行存储。 less是stl里面的一个函数对象,利用定义的 < 运算符进行比较。在我们插入<key, value>键值对时,就会按照key的大小顺序进行存储。
这也是作为key的类型必须能够进行 < 运算比较【可以通过重载实现】的原因。若不能,则需要自己写比较函数,否则编译报错
这样,若是不想按照定义的 < 运算符进行比较,则可自己加入别的比较函数例如less<KEY_TYPE>,甚至可以写一个Compare()函数并且调用。

template <class T> struct XXX : binary_function <T,T,bool> {    bool operator() (const T& x, const T& y) const      {return XXX;}  };  

至于按照value,暂时我用不到应该。

解题代码

#include<iostream>#include<cstdio>#include<cstring>#include<map>using namespace std;int main(){    int n,temp;    map<int,int>dat;    map<int, int>::iterator iter;    while(scanf("%d",&n)!=EOF){        dat.clear();        for(int i=0;i<n;i++){            scanf("%d",&temp);            if(dat.count(temp))                dat[temp]++;            else                dat[temp]=1;        }        for(iter = dat.begin(); iter != dat.end(); iter++) {            cout<<iter->first<<" "<<iter->second<<endl;        }     }    return 0;}

这里写图片描述

随便说说

那天下午刚好看完map然后晚上写题目就用到了。突然兴奋。果然,多了解东西比用已经知道的东西去解决问题有用、有效率。

再来一个随便说说

看到了别的大佬更高效的方法。今晚【2017.11.25】晚上算法组讨论会上听听看,听完了晚上回来再写一个别的吧。
喵呜~

阅读全文
0 0
原创粉丝点击