常用的C++ STL及例题
1. 顺序式容器
(1) vector(动态数组)
功能:
-
定义整型数组
①vector<int> a;
定义一个动态数组a,自动默认初始化为空
②vector<int> a(100);
定义一个动态数组a,有100个为0的元素
③vector<int> a(100, 6);
定义一个动态数组,有100个为6的元素 -
定义string型数组
①vector<string> a(10, "null");
10个值为null的元素
②vector<string> a(100,"hello");
10个值为hello的元素
③vector<string> b(a.begin(), a.end());
b是a的复制 -
定义结构型数组:
struct point {int x, y;};
vector<point> a;
a是用来存坐标的 -
赋值:
a.push_back(值);
在尾部添加元素 -
统计元素的个数:
a.size();
-
判断vector是否为空:
a.empty();
-
a.insert(a.begin() + i, k);
在第i个元素前面插入k -
a.insert(a.end(), 10, 5);
在尾部插入10个值为5的元素 -
a.pop_back();
删除末尾元素 -
a.erase(a.begin() + i, a.end() + j);
删除区间[i, j - 1]的元素 -
a.erase(a.begin()+2);
删除第3个元素 -
a.resize(n);
将数组大小调为n -
a.clear();
清空 -
reverse(a.begin(), a.end());
用函数reverse()翻转数组 -
sort(a.begin(), a.end());
排序
vector 例题
圆桌问题
Problem Description
圆桌上围坐着2n个人。其中n个人是好人,另外n个人是坏人。如果从第一个人开始数数,数到第m个人,则立即处死该人;然后从被处死的人之后开始数数,再将数到的第m个人处死……依此方法不断处死围坐在圆桌上的人。试问预先应如何安排这些好人与坏人的座位,能使得在处死n个人之后,圆桌上围坐的剩余的n个人全是好人。
Input
多组数据,每组数据输入:好人和坏人的人数n(<=32767)、步长m(<=32767);
Output
对于每一组数据,输出2n个大写字母,‘G’表示好人,‘B’表示坏人,50个字母为一行,不允许出现空白字符。相邻数据间留有一空行。
Sample Input
2 3
2 4
Sample Output
GBBG
BGGB
约瑟夫环问题
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<vector>
#include<algorithm>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define int ll
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MOD 1e9 + 7
#define mem(a, b) memset(a, b, sizeof a)
using namespace std;
int read(){int w = 1, s = 0;char ch = getchar();while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0';ch = getchar(); }return s * w;}
const int N = 70000;
vector<int> v;
bool ans[N];
signed main() {
int n, m;
while (~scanf("%lld%lld", &n, &m)) {
v.clear(); //清空
for (int i = 1; i <= n + n; i++) {
v.push_back(i);
ans[i] = true;//先都初始化为好人,true为好人,false为坏人
}
int cnt = v.size(), cur = 0;
//当坏人还没杀完,就一直循环
while (cnt > n) {
cur = (cur + m - 1) % cnt;//因为圆桌是一个环,所以要取余
ans[v[cur]] = false;//把这个位置记为坏人
//v.erase(a.begin()+i); 删除第i个元素
v.erase(v.begin() + cur); //删除第cur个元素
cnt--;
}
//输出
for (int i = 1; i <= n + n; i++) {
if (ans[i]) printf("G");
else printf("B");
if (i % 50 == 0) printf("\n");
}
//这题的格式有点问题
if((n << 1) % 50 != 0)
printf("\n");
printf("\n");
}
return 0;
}
(2) stack(栈)
栈的相关操作:
#include<stack> 头文件
stack<Type> s; 定义一个栈,Type为数据类型
s.top(); 返回栈顶元素,但不会在栈里删除该元素
s.pop(); 删除栈顶元素,但不会返回。
出栈(两步操作):先用s.top()获得栈顶元素,再用s.pop()弹栈
s.size(); 返回栈中元素的个数
s.empty(); 判断栈是否为空
栈 —— 简单例题(HDU 1062)
题意:翻转字符串
题解:用栈的先进后出的特点来做
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define int ll
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MOD 1e9 + 7
#define mem(a, b) memset(a, b, sizeof a)
#define print(n) printf("%lld\n", n);
using namespace std;
int read(){int w = 1, s = 0;char ch = getchar();while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0';ch = getchar(); }return s * w;}
const int N = 1010;
char str[N];
signed main() {
int t = read();
while (t--) {
char ch;
stack<char> s;
while (true) {
ch = getchar();//每次读入一个字符
if (ch == ' ' || ch == '\n' || ch == EOF) {
while (!s.empty()) {
printf("%c", s.top());//输出栈顶元素
s.pop();//弹栈
}
//结束
if (ch == '\n' || ch == EOF) break;
printf(" ");
}
else s.push(ch);//入栈
}
printf("\n");
}
return 0;
}
栈较复杂例题(HDU 1237)
简单计算器
Problem Description
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
Input
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
Output
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
Sample Input
1 + 2
4 + 2 * 5 - 7 / 11
0
Sample Output
3.00
13.36
对数字运算进行模拟:
① 如果遇到 ’ + ’ 或 ’ - ',先将相应的数字push入栈(如果是 ’ - ’ 则push数字的相反数)
② 如果遇到优先级大的 ’ * ’ 或 ’ / ’ 先将相应数字与栈顶元素进行运算后将结果push进入
③ 最后将栈中所有元素相加。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
#include<algorithm>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define int ll
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MOD 1e9 + 7
using namespace std;
int read()
{
int w = 1, s = 0;
char ch = getchar();
while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0';ch = getchar(); }
return s * w;
}
signed main()
{
char c, s;
char s;
double n;
//开头特殊处理:0 +'\n'时结束;
while(~scanf("%lf%c",&n,&c)) {
if(n == 0 && c=='\n') break;
stack<double>stk;
double ans=0;
while(!stk.empty()) stk.pop();
stk.push(n);
while(~scanf("%c %lf",&s,&n)) {
if (s == '+') stk.push(n);
if (s == '-') stk.push(-n);
if (s == '*') {
double tmp = stk.top() * n;
stk.pop();
stk.push(tmp);
}
if (s=='/') {
double tmp = stk.top() * 1.0 / n;
stk.pop();
stk.push(tmp);
}
c = getchar();
if (c == '\n') break;
}
while (!stk.empty()) {
ans += stk.top();
st.pop();
}
printf("%.2lf\n",ans);
}
return 0;
}
(3) queue(队列)
queue的操作:
#include<queue> 头文件
queue<Type> q; 定义队列
q.push(s); 把s放入队列
q.front(); 获取队首元素,但不会删除
q.pop(); 删除队首元素
q.back(); 返回队尾元素
q.size(); 返回队列中元素个数
q.empty(); 检查队列是否为空
栈和队列的简单例题(HDU 1702)
题意:模拟栈和队列:
栈是 FILO(先进后出 First In Last Out)
队列是 FIFO(先进先出 First In First Out)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<vector>
#include<functional>
#include<algorithm>
#include<stack>
#include<queue>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define int ll
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MOD 1000000007
#define mem(a, b) memset(a, b, sizeof a)
#define print(n) printf("%lld\n", n)
using namespace std;
int read()
{
int w = 1, s = 0;
char ch = getchar();
while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0';ch = getchar(); }
return s * w;
}
signed main() {
int t = read();
while (t--) {
string str;
queue<int> q;
stack<int> stk;
int n = read();
cin >> str;
for (int i = 1; i <= n; i++) {
string s;
cin >> s;
//队列
if (str == "FIFO") {
if (s == "IN") {
int a = read();
q.push(a);//IN,放进队列
} else {
if (q.empty()) printf("None\n");//如果队列为空,此时还要求输出的话,那么就是None
else {
printf("%lld\n", q.front());//输出队首元素
q.pop(); //删除队首元素
}
}
} else {
if (s == "IN") {
int a = read();
stk.push(a);//IN,放入栈中
} else {
if (stk.empty()) printf("None\n");//如果栈为空,此时还要求输出的话,那么就是None
else {
printf("%lld\n", stk.top());//输出栈顶元素
stk.pop();//弹栈:删除栈顶元素
}
}
}
}
}
return 0;
}
2. 关联式容器
(1) set(集合)
- set与数组不同的是,在set中每个元素的值都是唯一的。
- set插入数据时,能够根据元素的值自动进行排序。
- set中数元素的值并不能直接被改变。
set的有关操作:
set<Type> a; 定义一个set
a.insert(x); 把x放进set
a.erase(x); 删除元素x
a.clear(); 清空set
a.empty(); 判断set是否为空
a.size(); 返回set中元素个数
a.find(x); 返回一个迭代器,指向键值x
a.lower_bound(x); 返回一个迭代器,指向键值不小于x的第一个元素
a.upper_bound(x); 返回一个迭代器,指向键值不大于x的第一个元素
set 简单例题 (HDU 2094)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<vector>
#include<functional>
#include<algorithm>
#include<stack>
#include<set>
#include<queue>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define int ll
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MOD 1000000007
#define mem(a, b) memset(a, b, sizeof a)
#define print(n) printf("%lld\n", n)
using namespace std;
int read()
{
int w = 1, s = 0;
char ch = getchar();
while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0';ch = getchar(); }
return s * w;
}
signed main() {
int n;
while (cin >> n && n) {
string winner, loser;
set<string> all, lose;
//利用了set中每个元素的值都是唯一的
for (int i = 1; i <= n; i++) {
cin >> winner >> loser;
//把所有人放入all集合中
all.insert(winner);
all.insert(loser);
//把输的人放到lose集合中
lose.insert(loser);
}
//冠军没输过,如果能确定冠军,就是其他人都输过了,那么all.size() - lose.size() == 1
if (all.size() - lose.size() == 1) printf("Yes\n");
else printf("No\n");
//清空两个集合
all.clear();
lose.clear();
}
return 0;
}
(2) map(一对一映射)
之所以要用到map,这么一个简单的例子:有n个学生,每个学生有姓名name和学号id,现在给出学生的name,要找对应的id。
那就是要把该学生的 name 和 id 通过一个东西来绑定。
如果没有用map的话,那么可以用结构体
struct Student{
string name;
int id;
}s[N];
但是如果用结构体的话,给出 name 来找到 id 就需要线性查找这个时间复杂度是 O ( n ) O(n) O(n) 的。
如果用map的话,可以对这个优化。因为map效率高的原因是它用平衡二叉搜索树来存储和访问。
map的相关操作:
map<string, int> stu; 定义map<Type, Type>;
stu["QYIF"] = 09 绑定了name为 "QYIF" 的人,它的学号为 9号
用map就可以直接用 stu["QYIF"]
来表示 "QYIF"
这个人的学号。
map + 迭代器的简单例题 (HDU 2648)
题意:这个叫 Dandelion 的女孩,喜欢购物,她很喜欢这个叫 memory 的商店,临近年关,现在她想知道这家商店每天的价格排名。
题解:给这个memory商店初始化排名为1,用迭代器遍历,如果it->second (其他商店的价格比memory高)那么就rank++;就可以了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<vector>
#include<functional>
#include<algorithm>
#include<stack>
#include<set>
#include<queue>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define int ll
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MOD 1000000007
#define mem(a, b) memset(a, b, sizeof a)
#define print(n) printf("%lld\n", n)
using namespace std;
signed main() {
IOS;
int n, m, price;
while (cin >> n) {
map<string, int> shop;
string str;
for (int i = 1; i <= n; i++) cin >> str;
int m;
cin >> m;
while (m--) {
for (int i = 1; i <= n; i++) {
cin >> price >> str;
shop[str] += price;//给商店加上价格
}
int rank = 1;
map<string, int>::iterator it;//迭代器
//遍历
for (it = shop.begin(); it != shop.end(); it++) {
if (it->second > shop["memory"]) rank++;//如果遇到比memory这个商店的价格高就+1
}
printf("%lld\n" ,rank);
}
}
return 0;
}
3. sort() 排序函数
#include<algorithm> 头文件
sort(a, a + n) 格式1
sort(a, a + n, cmp) 格式2 (cmp为排序的规则)
拓展用法:
vector<int> a = {3, 2, 4, 6, 7}
sort(a.begin(), a.end()); 正常用法
sort(a.begin(), a.end(), 4); 对前4个元素进行排序,输出2 3 4 6 7
sort(a.begin(), a.end(), less<int>); 从小到大排序
sort(a.begin(), a.end(), greater<int>); 从大到小排序
sort(a.begin(), a.end(), cmp) 自定义排序,cmp是自定义函数
对结构变量排序:
struct stu{
string name;
int id;
};
bool cmp(struct stu* a, struct stu *b) {
//自定义排序,例如id从小到大排序
return a->id < b->id;
}
vector<struct Stu*> message; //将学生信息存入message
sort(message.begin(), message.end(), cmp);
4. next_permutation()和prev_permutation()
next_permutation()
下一个排列组合。
prev_permutation()
上一个排列组合。
例如3个字符 a、b、c next_permutation()
能按照字典序返回6个组合,分别是:abc、acb、bac、bca、cab、cba