简介

STL是Standard Template Library的简称,中文名标准模板库,从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。STL是C++的一部分,因此不用安装额外的库文件。

---------来自《百度百科》


那就直接开讲了呐

1.queue 队列

头文件:

#include <queue>
using namespace std;

简介:先进先出的无限长度数组。。。

基本操作函数:

  • q.push():从队尾入队
  • q.pop():从对头出队
  • q.front():队头元素
  • q.back():队尾元素
  • q.empty:判断是否为空
  • q.size():求队列长度

题目:Blah 数集

数学家高斯小时候偶然间发现一种有趣的自然数集合 Blah。对于以 a 为基的集合 Blah 定义如下:

1)a 是集合 Blah 的基,且 a 是 Blah 的第一个元素;

2)如果 x 在集合 Blah 中,则 2x+1 和 3x+1 也都在集合 Blah 中;

3)没有其他元素在集合 Blah 中了。

现在小高斯想知道如果将集合 Blah 中元素按照升序排列,第 n 个元素会是多少?注意:集合中没有重复的元素。

  • 输入格式

    一行两个正整数,分别表示集合的基 a 以及所求元素序号 n,1≤a≤50,1≤n≤1000000。

  • 输出格式

    一行一个正整数,表示集合 Blah 的第 n 个元素值。

样例输入

28 5437

样例输出

900585

分析

这是一道很显然的一道队列题目,重点是熟悉队列的操作

开两个队列,在每次入队后,找出两个队列队头较小的那一个,作为下一次入队的依据

因为是升序,所以题目就是要求第 n 小的,也就是我们第 n-1 次操作找到的两个队列队头较小的哪一个

AC代码

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std; queue<int> x; // 2a + 1
queue<int> y; // 3a + 1 int main() {
int a, n;
scanf("%d %d", &a, &n);
for(int i = 1; i < n; i++) {
x.push(a * 2 + 1); // 分别入队
y.push(a * 3 + 1);
if(x.front() < y.front()) { // 取出两个序列的队头元素,进行比较
a = x.front();
x.pop(); // 先查找,再删除队头元素
}
else if(x.front() > y.front()) {
a = y.front();
y.pop();
}
else { // 如果相等,两边都要删除队头元素
a = x.front();
x.pop();
y.pop();
}
}
printf("%d", a);
return 0;
}

2.priority_queue 优先队列

头文件:

#include <queue>
using namespace std;

简介:保证队头一定是最大值,或队头一定是最小值的队列,内部由二叉堆实现

基本操作函数:

  • q.push():从队尾入队
  • q.pop():从对头出队
  • q.top():队头元素
  • q.empty:判断是否为空
  • q.size():求队列长度

特别注意:优先队列默认大根堆,如果要改为小根堆,需要建立自定义结构体,然后重载运算符

struct node {
int id, v;
bool operator<(const node x) const {return v > x.v;}
};
priority_queue <node> q;

当然也可以写成

priority_queue<int, vector<int>, greater<int> > q;

题目:有序表的最小和

题目描述

给出两个长度为 n 的有序表 A 和 B,在 A 和 B 中各任取一个元素,可以得到 n*n 个和,求这些和中最小的 n 个。

输入格式

第 1 行包含 1 个整数正 n(n≤400000)。 第 2 行与第 3 行分别有 n 个整数,各代表有序表 A 和 B。一行中的每两个整数之间用一个空格隔开,大小在长整型范围内,数据保证有序表单调递增。

输出格式

输出共 n 行,每行一个整数,第 i 行为第 i 小的和。 数据保证在 long long 范围内。

样例输入

3
1 2 5
2 4 7

样例输出

3
4
5

分析

可以枚举所有和,再压入小根堆优先队列,因为优先队列的性质,所以输出前n个队头元素即可。但因为n的范围是400000,所以这种n方的算法一定会TLE。。。

由于两个已知数列的有序性,所以可得

第一行    A[1]+B[1] ≤ A[1]+B[2] ≤ A[1]+B[3] ≤ ······
第二行 A[2]+B[1] ≤ A[2]+B[2] ≤ A[2]+B[3] ≤ ······
······
第n行 A[n]+B[1] ≤ A[n]+B[2] ≤ A[n]+B[3] ≤ ······

那就先把每一行的第一个(即最小值)压入优先队列,取出队头元素(最小值)并输出,如果取的是第i行的元素,就把第i行的下一个元素压入,让堆中始终保持n个元素和。

AC代码

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std; const int MAXN = 400005;
long long a[MAXN], b[MAXN], c[MAXN]; struct node {
int id, v; // id代表是第几行,v代表实际值
bool operator<(const node x) const {return v > x.v;} // 运算符重载
};
priority_queue <node> q; // 优先队列的定义 int main() {
int n, m;
scanf ("%d", &n);
for(int i = 1; i <= n; i++) scanf ("%lld", &a[i]);
for(int i = 1; i <= n; i++) scanf ("%lld", &b[i]);
for(int i = 1; i <= n; i++) {
c[i] = 2;
node t;
t.v = a[i] + b[1]; // 将每行第一个进入队列
t.id = i; // 存储是第几行的
q.push(t);
}
for(int i = 1; i <= n; i++) {
node t = q.top(); // 取出队头元素
q.pop();
printf("%d\n", t.v);
t.v = a[t.id] + b[c[t.id]++]; // 计算出下一个
q.push(t); // 进入队列
}
return 0;
}

3.stack 栈

头文件:

#include <stack>
using namespace std;

简介:后进先出的无限长度数组。。。

基本操作函数:

  • s.push():从栈顶入栈
  • s.pop():从栈顶出栈
  • s.top():栈顶元素
  • s.empty:判断是否为空

题目:简单计算器

题目描述

读入一个只包含+、-、*、/、的非负整数计算表达式,计算该表达式的值。

  • 输入格式

    测试数据有多组,每组占一行。

    每行不超过200个字符,整数和运算符之间用一个空格分隔。

    没有非法表达式。

    当一行中只有一个0时,表示输入结束,相应的结果不要输出。

  • 输出格式

    对于每组测试数据输出一行,即该表达式的值,精确到小数点后两位。

输入样例

30 / 90 - 26 + 97 - 5 - 6 - 13 / 88 * 6 + 51 / 29 + 79 * 87 + 57 * 92
0

输出样例

12178.21

分析

当读入到一个符号的时候,从数字栈顶揪出一个数,进行计算,再重新压入栈呐~

AC代码

#include <cstdio>
#include <stack>
using namespace std;
stack<double> s; // 栈的定义 int main() {
double x;
char c;
while(scanf ("%lf%c", &x, &c)) {
if(x == 0 && c != ' ') return 0;
double m;
char a, b;
s.push(x);
while(scanf ("%c %lf%c", &a, &m, &b) != EOF) { // 输入
if(a == '+') s.push(m); // 如果是加号,压入正m
else if(a == '-') s.push(-m); // 是减号,压入负m
else if(a == '*' && !s.empty()) { // 如果是乘号,且数字栈不为空
double t = s.top(); // 取出一个
s.pop();
t *= m;
s.push(t); // 压入 t*m
}
else if(a == '/' && !s.empty()) { // 如果是除号,且数字栈不为空
double t = s.top(); // 取出一个
s.pop();
t /= m;
s.push(t); // 压入 t/m
}
if(b != ' ') break;
}
double ans = 0;
while(!s.empty()) {
ans += s.top(); // 累计数字栈里的答案即可
s.pop();
}
printf("%.2lf\n", ans);
}
return 0;
}

4.vector 动态数组

头文件:

#include <vector>
using namespace std;

简介:无限长度的数组。。。

基本操作函数:

  • v.push_back():插入元素到数组的尾部
  • v.pop_back():删除数组尾部的元素
  • v.size():求数组长度
  • v.empty():判断数组是否为空
  • v.clear():把数组清空
  • 迭代器:迭代器就像STL的指针,返回一个地址,可以用*操作符得到其对应的具体的值

    声明方法:vector::iterator it
  • v.begin():返回指向数组第一个元素的迭代器
  • v.end():返回指向数组最后一个元素的迭代器
  • v.front():返回数组第一个元素
  • v.back():返回数组最后一个元素

题目:上网统计

题目描述

在一个网络系统中有N个用户1≤N≤1000、M次上网记录1≤M≤5000。每个用户可以自己注册一个用户名,每个用户名是一个只含小写字母的字符串。每个上网的账号每次上网都会浏览网页,网页名是一串只含小写字母的字符串,每次上网日志都会留下记录,现在请你统计一次上网日志中,每个用户浏览了多少个网页。(输出按照输入顺序输出)

  • 输入格式

    第一行N和M 第2行到第M+1行为M条上网日志,每行两个字符串,用空格隔开

  • 输出格式

    N个ID的上网记录,具体看样例

样例输入

5 7
guomao wangyi
lifan tengxun
zhoushijian souhu
zhangshilin tengxun
guomao souhu
zhoushijian wangyi
liuyang bilibili

样例输出

guomao wangyi souhu
lifan tengxun
zhoushijian souhu wangyi
zhangshilin tengxun
liuyang bilibili

分析

此题GM讲过的哦~

看看各种函数及迭代器的使用。。。

AC代码

#include <cstdio>
#include <string>
#include <iostream>
#include <vector>
using namespace std; const int MAXN = 1005;
vector <string> v[MAXN]; // 动态数组的定义
struct node{
int index;
string c;
} s[MAXN]; int main() {
int n, m, t = 0;
scanf ("%d %d", &n, &m);
for(int i = 1; i <= m; i++) {
string ch, k;
getchar();
cin >> ch;
cin >> k;
int index_ = 0;
for(int j = 1; j <= t; j++) {
if(ch == s[j].c)
index_ = s[j].index;
}
if(index_ == 0) {
t++;
index_ = t;
s[index_].index = t;
s[index_].c = ch;
}
v[index_].push_back(k); // 在最后插入一个元素
}
for(int i = 1; i <= n; i++) {
cout << s[i].c << " ";
for(vector<string>::iterator it = v[s[i].index].begin(); it != v[s[i].index].end(); it++) {
// 利用迭代器进行输出,将其初值置为指向第一个元素的迭代器,如果当前迭代器没有指向最后一个元素,迭代器加加
cout << *it << " "; // 输出当前迭代器对应的具体的值
}
cout << endl;
}
return 0;
}

5.map

头文件:

#include <map>
using namespace std;

简介:映射,可以看作数组下标为任意类型的数组

基本操作函数:

  • v.empty():判断数组是否为空
  • v.clear():把数组清空
  • 迭代器声明方法:map<int, int>::iterator it

    且 it 对应的具体的值是一个pair
  • v.begin():返回指向数组第一个元素的迭代器
  • v.end():返回指向数组最后一个元素的迭代器
  • v.insert():插入一个元素

题目:T1 查字典

题目描述

gm英语非常不好,为了应对全国英文四级考试,他手里有一本英语字典,现在有很多单词要查。请编写程序帮助他快速找到要查的单词所在的页码。

  • 输入格式

    第一行1个整数N,N≤10000,表示字典中一共有多少单词。

    接下来每两行1个单词,其中:第一行是长度≤100的字符串,表示这个单词,全是小写字母,单词不会重复。 第二行是1个整数,表示这个单词在字典中的页码。

    接下来是一个整数M,M≤N,表示要查的单词数。 接下来M行,每行一个字符串,表示要查的单词,保证在字典中存在。

  • 输出格式

    M行,每行1个整数,表示第i个单词在字典中的页码。

样例输入

2
scan
10
word
15
2
scan
word

样例输出

10
15

分析

是裸题诶……以单词为下标保存页码的数组就可以了

AC代码

#include <cstdio>
#include <map>
#include <string>
#include <iostream>
using namespace std; map<string, int> mp; // 映射的定义 int main() {
int n;
scanf ("%d", &n);
for(int i = 1; i <= n; i++) {
string s;
cin >> s;
int x;
cin >> x;
mp[s] = x;
// 可以像数组一样赋值
// 此题也可以利用 pair 写为 mp.insert(make_pair(s,x));
}
int m;
scanf ("%d", &m);
for(int i = 1; i <= m; i++) {
string s;
cin >> s;
printf("%d\n", mp[s]);
}
return 0;
}
T2 Let the Balloon Rise

小气球~~气球~

题目描述

在ACM比赛中,你每解决一道题,你就可以获得一个气球,不同颜色的气球代表你解决了不同的问题。在GM同学参加的一场ACM比赛中,他发现场面上有N个气球,并熟练的说出了气球的颜色。

请你编写一个程序,找出气球数量最多的颜色。

  • 输入格式

    有多组样例输入。

    每组样例第一行输入一个整数N (0 < N <= 1000) ,代表一共有N个气球。若N=0,则代表输入结束。

    接下来N行每行输入一个不多于15个字母的字符串代表颜色。

  • 输出格式

    对于每组样例数据,在单独的一行内输出数量最多的那种颜色的气球。(数据保证输出是唯一的)

样例输入

5
green
red
blue
red
red
3
pink
orange
pink
0

样例输出

red
pink

分析

还是裸a!~!!

以颜色为下标存储出现次数的数组

#include <cstdio>
#include <map>
#include <string>
#include <iostream>
using namespace std; const int MAXN = 10005;
string s[MAXN]; int main() {
int n;
while(scanf ("%d", &n) != EOF) {
if(n == 0) break;
map<string, int> mp; // map 的定义
for(int i = 1; i <= n; i++) {
cin >> s[i];
mp[s[i]]++; // 颜色 s[i] 出现的次数增加
}
string ch;
int ma = 0;
for(int i = 1; i <= n; i++) {
if(mp[s[i]] >= ma) {
ma = mp[s[i]];
ch = s[i];
}
}
cout << ch << endl;
}
return 0;
}

6.set 有序集合

头文件:

#include <set>
using namespace std;

简介:set 有序的无重复的集合,multiset 有序的可重复的集合

基本操作函数:(set 和 multiset 相同)

  • s.size():求集合长度
  • s.empty():判断集合是否为空
  • s.clear():把集合清空
  • 迭代器声明方法:set::iterator it
  • s.begin():返回指向集合第一个元素的迭代器
  • s.end():返回指向集合最后一个元素的迭代器
  • s.insert():插入一个元素
  • s.count():返回集合中等于某个数的元素个数

特别注意:set 和 multiset 也需要重载运算符


题目:【STL综合】题海战

题目描述

某信息学奥赛教练经验丰富,他的内部题库有 m 道题。他有 n 个学生,第 i 个学生已经做过p[i]道题。由于马上要进行noip考试,该教练准备举行 k 场比赛和训练。每场比赛或训练都会有一些他的学生参加,但是如何选题令他非常烦恼。对于每场比赛,他要保证所出的题没有任何一道已有任何一个学生做过;而对于每场训练,他要保证所出的所有题都被每一个参赛学生做过。

  • 输入格式

    第1行2个正整数n和m,表示学生数和题库中的题目总量。

    第2~n+1行,先是1个正整数p,然后p个整数表示第i个学生的做题记录(可以重复做同一道题)。

    第n+2行,1个正整数k,表示要举行比赛和训练的总场数(可能有学生重复报名)。

    接下来的k行,每行的第1个整数type表示是训练或者比赛(1为训练,0为比赛)。第二个数q表示参赛学生数,然后q个正整数表示参赛学生编号。每一行的两个数之间有一个空格。

  • 输出格式

    共k行,每行表示本次训练或比赛可选的最多题目(由小到大排序,中间用一个空格隔开,如果没有输出一个空行)。

样例输入

5 10
2 3 7
1 3
2 4 7
3 3 6 10
7 1 2 3 4 7 8 9
6
0 3 3 4 5
0 3 1 3 4
1 2 1 3
0 1 5
1 1 2
1 2 3 5

样例输出

5
1 2 5 8 9
7
5 6 10
3
4 7

分析

利用动态数组存储每一个学生做过的题目

在输出时利用映射求出每个参加训练的学生都做过的题

利用有序集合求出每个参加比赛的学生都没做过的题

#include <cstdio>
#include <set>
#include <map>
#include <vector>
using namespace std; const int MAXN = 10005;
vector<int> v[MAXN]; // 动态数组的定义
set<int> s; // 有序集合的定义
map<int, int> mp; // 映射的定义 int main() {
int n, m;
scanf ("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
int n_;
scanf ("%d", &n_);
for(int j = 1; j <= n_; j++) {
int x;
scanf ("%d", &x);
v[i].push_back(x);
}
}
int k;
scanf ("%d", &k);
for(int i = 1; i <= k; i++) {
int flag;
s.clear();
mp.clear();
scanf ("%d", &flag);
if(flag == 0) {
int n_;
scanf ("%d", &n_);
for(int j = 1; j <= n_; j++) {
int stu;
scanf ("%d", &stu);
for(int k_ = 0; k_ < v[stu].size(); k_++) // 统计每道题被几个学生做过
mp[v[stu][k_]]++;
}
for(int j = 1; j <= m; j++) {
if(mp[j] == n_) // 如果都做过就输出
printf("%d ", j);
}
printf("\n");
}
else { int n_;
scanf ("%d", &n_);
for(int j = 1; j <= n_; j++) {
int stu;
scanf ("%d", &stu);
for(int k_ = 0; k_ < v[stu].size(); k_++)
s.insert(v[stu][k_]); // 加入有序集合
}
bool flag[MAXN] = {0};
for(set<int>::iterator it = s.begin(); it != s.end(); it++) // 迭代器遍历,把所有有学生做过的题目标记
flag[*it] = true;
for(int j = 1; j <= m; j++) {
if(flag[j] == false) // 未被标记的即可输出
printf("%d ", j);
}
printf("\n");
}
}
return 0;
}

突破极限,一旦放弃了就意味着结束,说不定身体里还隐藏着连自己都没有察觉到的力量,不要被所谓的极限所禁锢。

浅谈 STL的更多相关文章

  1. 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...

  2. C++ STL中的常用容器浅谈

    STL是C/C++开发中一个非常重要的模板,而其中定义的各种容器也是非常方便我们大家使用.下面,我们就浅谈某些常用的容器.这里我们不涉及容器的基本操作之类,只是要讨论一下各个容器其各自的特点.STL中 ...

  3. 浅谈C++ STL string容器

    浅谈C++ STL string容器 本篇随笔简单讲解一下\(C++STL\)中\(string\)容器的使用方法及技巧. string容器的概念 其实\(string\)并不是\(STL\)的一种容 ...

  4. 浅谈C++ STL list 容器

    浅谈C++ STL list 容器 本篇随笔简单讲解一下\(C++STL\)中\(list\)容器的使用方法和使用技巧. list容器的概念 学习过\(C++STL\)的很多同学都知道,\(STL\) ...

  5. 浅谈C++ STL vector 容器

    浅谈C++ STL vector 容器 本篇随笔简单介绍一下\(C++STL\)中\(vector\)容器的使用方法和常见的使用技巧.\(vector\)容器是\(C++STL\)的一种比较基本的容器 ...

  6. 浅谈C++ STL queue 容器

    浅谈C++ STL queue 容器 本篇随笔简单介绍一下\(C++STL\)中\(queue\)容器的使用方法和常见的使用技巧.\(queue\)容器是\(C++STL\)的一种比较基本的容器.我们 ...

  7. 浅谈C++ STL stack 容器

    浅谈C++ STL stack 容器 本篇随笔简单介绍一下\(C++STL\)中\(stack\)容器的使用方法和常见的使用技巧. stack容器的概念 \(stack\)在英文中是栈的意思.栈是一种 ...

  8. 浅谈C++ STL deque 容器

    浅谈C++ STL deque 容器 本篇随笔简单介绍一下\(C++STL\)中\(deque\)容器的使用方法及常见使用技巧. deque容器的概念 \(deque\)的意义是:双端队列.队列是我们 ...

  9. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

随机推荐

  1. 进程相关的API函数

    0x01. ID与句柄 如果我们成功创建一个进程之后,CreateProcess会返回四个数据,id和句柄 句柄的话就是 当前进程私有的句柄表索引(这是当前进程,给别进程也没用) 每个进程都有一张自己 ...

  2. js音乐播放器【简洁】

    辞职的第二天没有去找工作还,准备回家. 但到了火车站才发现沃特玛的买的票不是在这个火车站坐. 这就耽误了行程...... 说出来真舒服!!!淦 代码 这里已经上传到码云了,大家可以直接引用. 目前只有 ...

  3. 想学 iOS 开发高阶一点的东西,从何开始?

    前言 如果你正在学习 iOS, 或者正在从事IOS开发? 还是一个一个迷茫的待就业大学生,或是公司的到一个半老员工? 现在到了开发的一个阶段了,基本的东西很熟了,想着提高技术? 学习难一点的东西,不知 ...

  4. 汉诺塔问题实验--一个简洁的JAVA程序

    思路: 这里使用递归法 n==1的时候,直接把它从x移到z位置即可. 如果是n层,我们首先把上面的n- 1层移到y位置,然后把最 下面的那个最大的盘子,移到z位置,然后把y上面放的上面n-1层移到z位 ...

  5. 数据库会话数量过多,定期清理inactive会话

    1.1现象 存在一套11.2.0.4 RAC 2节点,数据库存在5000个会话数量,其中active正在执行的会话500个,其余均为非活跃会话. 大量inactive会话过多给Oracle数据库带来什 ...

  6. 你知道MySQL的LRU链表吗?

    相信大家对LRU链表是不陌生的,算是一种基础的数据结构! LRU:Least Recently Used 一.简述传统的LRU链表 LRU:Least Recently Used 相信大家对LRU链表 ...

  7. Servlet与通信协议概述

    Servlet 是一个java应用程序,一个Servlet应用有一个或多个Servlet程序,JSP页面会被转换和编译成Servlet程序. Servlet应用无法独立运行,必须运行在Servlet容 ...

  8. 对pipe downstream的思考&分析

       回到ngx_http_upstream_send_response,如果是buffering,就会进入后面的处理过程,准备一个ngx_event_pipe_t结构的数据,这个结构可以通过upst ...

  9. switch,case语句易误区

    switch case 语句语法格式如下: switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可 ...

  10. vdbench测试实时可视化显示

    前言 前一段时间碰到一个系统,用rados bench 去跑都还比较正常,但是一跑数据库就非常慢,测试工具会抛出延时过大的提示,经过排查发现,云平台中有一台虚拟机还运行着备份数据库的服务,而这个备份软 ...