文章目录
专题复习五(9.6):常用的STL容器及其相关操作
1 vector的常见用法
只有在vector和string中,才允许使用v.begin()+3这种迭代器加上整数的写法。
// 1.定义
vector<int> v1;
vector<Node> v2;
vector<vector<int> > v3;
vector<int> Adj[MAXV]; //声明一个邻接表
vector<int> v4(50); //声明一个初始大小为50的int向量
vector<int> v5(10, 1); //声明一个初始大小为10且值都是1的向量
vector<int> v6(v1); //声明v6并用v1向量初始化
vector<int> v7(v1.begin(), v1.begin() + 3); //用向量v1的第0个到第2个值初始化v7
int arr[5] = {1, 2, 3, 4, 5};
vector<int> v8(arr, arr + 5); //将arr数组的元素用于初始化v8向量: 1 2 3 4 5
vector<int> v9(&arr[1], &arr[4]); //将[ arr[1]~arr[4] )范围内的元素作为v9的初始值: 2 3 4
// 2.元素访问
vector<int> v1(10);
cout << v1[5] << v1[v1.size()-1]; //通过下标访问
vector<int>::iterator it = v1.begin(); //通过迭代器访问
for(int i=0; i<v1.size()-1; i++){
cout << *(it + i);
}
for(vector<int>::iterator it = v1.begin(); it != v1.end(); it++){
cout << *it;
}
// 3.常用函数
vector<int> v;
v.push_back(1); //时间复杂度O(1)
V.pop_back(); //时间复杂度O(1)
int s = v.size(); //时间复杂度O(1)
v.clear(); //时间复杂度O(N)
v.insert(v.begin()+2, -1); //时间复杂度O(N),插入后为1 2 -1 3 4 5
v.erase(v.begin()+2); //时间复杂度O(N),删除后为1 2 3 4 5
v.erase(v.begin(), v.begin()+3); //时间复杂度O(N),删除后为4 5
int max = *max_element(v.begin(), v.end()); //求最大元素
int max = *min_element(v.begin(), v.begin()+3); //求[0,3)之间的最小元素
reverse(v.begin(), v.end()); //将vector中的元素倒序
sort(v.begin(), v.end()); //采用的是从小到大的排序
//如果想从大到小排序,可以采用反转函数,也可以采用下面方法:
bool cmp(const int& a, const int& b) {
return a > b;
}
sort(v.begin(), v.end(), cmp);
2 set的常见用法
STL中的set使用方法详细!!!!_知足常乐的博客-CSDN博客
c++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。set内的元素自动递增排序,且去除了重复元素。
// 1.定义
set<int> s1;
set<Node> s2;
set<int> s3[MAXV];
// 2.元素访问
for(set<int>::iterator it = s3.begin(); it != s3.end(); it++){
cout << *it;
}
// 3.常用函数
s1.insert(1); //时间复杂度O(logN)
//时间复杂度O(logN),如果找到返回迭代器位置,否则返回s1.end()
set<int>::iterator it = s1.find(1);
//删除单个元素的方式有两种,一种参数为迭代器,一种参数为要删除的值
s1.erase(it); //时间复杂度O(1)
s1.erase(3); //时间复杂度O(logN)
s1.erase(it, s1.end()) //删除一个区间的元素,时间复杂度O(last-first)
int num = s1.size(); //时间复杂度O(1)
s1.clear(); //时间复杂度O(N)
//set默认的是递增排序,如果想从大到小排序,可以采用下面方法:
set<int, greater<int> > st;
//如果没有排序要求,使用unordered_set速度会快很多,因为其底层是Hash实现的。
unordered_set<int> st;
3 string的常见用法
stl之string类用法详细总结_Hao_09的专栏-CSDN博客_stl string
// 1.定义
string s; //生成一个空字符串s
string s = "123";
string s(str) //拷贝构造函数生成str的复制品
string s(str,index) //将字符串str内“始于位置index”的部分当作字符串的初值
string s(str,index, n) //将字符串str内“始于index且长度顶多n”的部分作为字符串的初值
string s(cstr) //将C字符串作为s的初值
string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。
string s(n,c) //生成一个字符串,包含n个c字符
string s(str.begin(),str.end()) //以区间begin():end() (不包含end())内的字符作为字符串s的初值
// 2.元素访问
for(int i=0; i<str.length(); i++){
printf("%c", str[i]);
}
cin >> str;
cout << str;
printf("%s",str.c_str()); //要用printf输出的话得使用c_str()将string类型转换为字符数组输出
string::iterator it;
// 3.常用函数
s1 = s2 + s3;
bool flag = s1 > s2;
s.length(); s.size();
//插入函数,时间复杂度为O(N)
string str = "abcxyz", str2 = "opq";
str.insert(3, str2); //abcopqxyz
str.insert(str.begin() + 3, str2.begin(), str2.end());
s.insert(0, 4 - s.length(), '0'); //用来给不足4位的时候前面补0~
//删除函数,时间复杂度为O(N)
str.erase(it);
str.erase(str.begin()+1, str.end());
str.erase(pos, length);
string str = "abcdefg";
str.erase(3,2); //abcfg
str.clear() //复杂度O(1)
str.substr(pos, length); //复杂度O(len);
//查找函数,时间复杂度为O(NM)
找到了返回下标,没找到返回string::npos
int main(void)
{
string s("dog bird chicken bird cat");
//字符串查找
cout << s.find("bird") << endl; //打印
cout << (int)s.find("pig") << endl; //打印-1
//字符查找
cout << s.find('i',7) << endl; //打印
//从字符串的末尾开始查找字符串
cout << s.rfind("bird") << endl; //打印
//从字符串的末尾开始查找字符
cout << s.rfind('i') << endl; //打印
//查找第个属于某子串的字符
cout << s.find_first_of("13r98") << endl; //找到字符r,打印
//查找第个不属于某字符串的字符
cout << s.find_first_not_of("dog bird 2006") << endl; //找到字符c,打印
//查找最后一个属于某子串的字符
cout << s.find_last_of("13r98") << endl; //字符r,打印
//查找最后一个不属于某字符串的字符
cout << s.find_last_not_of("tea") << endl; //字符c,打印
return 0;
}
//替换函数,时间复杂度为O(N)
int main(void)
{
string s("hello,boy!");
s.replace(6,3,"gril"); //boy替换为girl
cout << s << endl; //打印hello gril!
s.replace(10,1,3,'.'); //将"hello gril!"的'!'替换为'...'
cout << s << endl; //打印hello gril.
s.replace(s.begin(),s.begin()+5, "good morning");
cout << s << endl; //打印good morning girl...
return 0;
}
4 map的常见用法
cpp中的STL中map用法详解_Hello World-CSDN博客
map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的.map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。
根据key值快速查找记录,查找的复杂度基本是Log(N),不需要排序时使用unordered_map节省时间。
// 1.定义
map<int, int< mp;
// 2.元素访问
mp[10];
mp["c"];
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
printf("%c %d\n", it->first, it->second);
}
// 3.常用函数
map<char, int>::iterator it = mp.find('b'); //查找的是关键字是否出现,复杂的O(logN)
if(it != mp.end())
cout<<"Find, the value is "<<it->second<<endl;
else
cout<<"Do not Find"<<endl;
map["a"] == 0 如果a不存在于map
mp.erase(it);
mp.erase(key);
mp.erase(first, last);
mp.size();
mp.clear();
例如:map中已经插入了1,2,3,4的话,如果lower_bound(2)的话,返回的2,而upper-bound(2)的话,返回的就是3
it = mp.lower_bound(1);
5 queue的常见用法
STL详解(三) 队列容器queue_流年的博客-CSDN博客
STL deque用法_pigofzhou的博客-CSDN博客
主要用于BFS。
// 1.定义
queue<int> q;
// 2.元素访问
int a = q.front();
int b = q.back();
// 3.常用函数,复杂的都为O(1)
q.push(x);
q.pop();
q.empty();
q.size();
6 priority_queue的常见用法
STL priority_queue 常见用法详解 - 哨音 - 博客园 (cnblogs.com)
priority_queue底层是用堆来实现的。 默认的是大顶堆。
主要用于解决一些贪心问题,以及Dijkstra算法的优化,使用top函数前记得先判断队列是否为空。
// 1.定义
priority_queue<int> q;
priority_queue<Node> q;
// 2.元素访问
int a = q.top();
// 3.常用函数
q.push(x);
q.top();
q.pop();
q.empty();
q.size();
// 4.优先级设置
priority_queue<int, vector<int>, greater<int> > q; //设置为小顶堆
struct fruit{ //设置价格低的为优先级高
string name;
int price;
friend bool operator < (const fruit &f1, const fruit &f2){
return f1.price > f2.price;
}
};
priority_queue<fruit> q1;
struct fruit{ //设置价格低的为优先级高
string name;
int price;
};
struct cmp{
bool operator () (const fruit &f1, const fruit &f2){
return f1.price > f2.price;
}
};
priority_queue<fruit, vector<fruit>, cmp> q2;
7 stack的常见用法
stack的常见用途是用来模拟一些递归,防止程序对栈内存的限制而导致程序运行出错(不过这种应用一般出现较少)。
// 1.定义
stack<int> st;
stack<Node> st;
// 2.元素访问
int a = st.top();
// 3.常用函数
st.push(x);
st.top();
st.pop();
st.empty();
st.size();
8 pair的常见用法
pair可以看作内部有两个元素的结构体。pair中只有两个元素,分别是first和second,按正常结构体的方式去访问即可。
// 1.定义
pair<int, int> st;
pair<string, int> p("haha",5);
// 2.元素访问
p = make_pair("xixi",6);
cout << p.first << p.second;
// 3.常用函数
== != < <= > >=比较大小,先以first的大小为标准
mp.insert(make_pair("heihei,7"));
9 algorithm头文件下的常用函数
- max(),min() 参数必须是两个,可以是浮点数。
- abs() 参数必须是整数,浮点数需要使用math头文件下的fabs。
- swap(a,b) 用来交换a,b的值
- reverse(it1, it2),将[it1,it2)内的元素翻转,适用于数组以及容器(vector, string)。
- next_permutation() 给出下一个序列
int a[10] = {1, 2, 3};
do{
printf("%d%d%d\n", a[0], a[1], a[2]);
}while(next_permutation(a, a+3));
- fill(a, a+MAXN, INF) 对数组或容器赋值。
- sort(a, a+5, cmp) 排序函数,主要用于结构体排序以及容器的排序(vector,string, deque可以使用sort)。
- lower_bound(first, last, val) 用来寻找在数组或容器的[first, last)范围内第一个值大于等于val的元素的位置。
- upper_bound(first, last, val) 用来寻找在数组或容器的[first, last)范围内第一个值大于val的元素的位置。
- 如果没有找到则返回可以插入的位置,upper_bound返回的值减去lower_bound返回的值即为值为val的元素个数。
10 例题解析
10.1 A1039 Course List for Student (25 分)
可以考虑字符串hash,用scanf读取节省时间,scanf读取string类型的话,需要先用resize分配内存,然后读取:
scanf("%s", &str[0]);
#include<bits/stdc++.h>
using namespace std;
int n, k;
unordered_map<string, set<int> > mp;
int getid(char *name) {
int id = 0;
for(int i = 0; i < 3; i++)
id = 26 * id + (name[i] - 'A');
id = id * 10 + (name[3] - '0');
return id;
}
int main(){
int courseId, m;
string name;
name.resize(4);
cin >> n >> k;
for(int i=1; i<=k; i++){
scanf("%d %d",&courseId, &m);
for(int j=0; j<m; j++){
scanf("%s",&name[0]);
mp[name].insert(courseId);
}
}
for(int i=0; i<n; i++){
scanf("%s",&name[0]);
printf("%s %d",name.c_str(), mp[name].size());
for(auto it = mp[name].begin(); it != mp[name].end(); it++){
printf(" %d",*it);
}
printf("\n");
}
}
10.2 A1047 Student List for Course (25 分)
直接用多个set会超时,先用vector存储,最后用sort排序一次就不会超时。
#include<bits/stdc++.h>
using namespace std;
int n, k;
vector<string> s[2505];
int main(){
string name;
int m, idx;
name.resize(5);
scanf("%d %d",&n,&k);
for(int i=0; i<n; i++){
scanf("%s %d",&name[0], &m);
for(int j=0; j<m; j++){
scanf("%d",&idx);
s[idx].push_back(name);
}
}
for(int i=1; i<=k; i++){
printf("%d %d\n",i,s[i].size());
sort(s[i].begin(), s[i].end());
for(int j = 0; j < s[i].size(); j++){
printf("%s\n",(s[i][j]).c_str());
}
}
}
10.3 A1063 Set Similarity (25 分)
得到交集之后,并集的元素数量用两个集合的元素数相加再减去交集元素数即可。
set_intersection, set_union真好用哈哈!
#include<bits/stdc++.h>
using namespace std;
set<int> st[55];
int n, m, k;
int main(){
int temp, a, b;
scanf("%d",&n);
for(int i=1; i<=n; i++){
scanf("%d",&m);
for(int j=0; j<m; j++){
scanf("%d",&temp);
st[i].insert(temp);
}
}
scanf("%d",&k);
for(int i=0; i<k; i++){
scanf("%d %d",&a,&b);
set<int> interSt, unionSt;
set_intersection(st[a].begin(), st[a].end(), st[b].begin(), st[b].end(), inserter(interSt, interSt.begin()));
//set_union(st[a].begin(), st[a].end(), st[b].begin(), st[b].end(), inserter(unionSt, unionSt.begin()));
printf("%.1f%%\n",interSt.size() * 100.0 / (st[a].size() + st[b].size() - interSt.size()));
}
}
10.4 A1060 Are They Equal (25 分)
这题挺恶心的,陷阱很多,要考虑的细节也很多,自己代码逻辑太混乱了就不放上来了…
1060. Are They Equal (25)-PAT甲级真题(科学计数法)_柳婼 の blog-CSDN博客
也可以像算法笔记上把主题部分和指数部分分开考虑。
#include <iostream>
#include <cstring>
using namespace std;
int main() {
int n, p = 0, q = 0;
char a[10000], b[10000], A[10000], B[10000];
scanf("%d%s%s", &n, a, b);
int cnta = strlen(a), cntb = strlen(b);
for(int i = 0; i < strlen(a); i++) {
if(a[i] == '.') {
cnta = i;
break;
}
}
for(int i = 0; i < strlen(b); i++) {
if(b[i] == '.') {
cntb = i;
break;
}
}
int indexa = 0, indexb = 0;
while(a[p] == '0' || a[p] == '.') p++;
while(b[q] == '0' || b[q] == '.') q++;
if(cnta >= p)
cnta = cnta - p;
else
cnta = cnta - p + 1;
if(cntb >= q)
cntb = cntb - q;
else
cntb = cntb - q + 1;
if(p == strlen(a))
cnta = 0;
if(q == strlen(b))
cntb = 0;
while(indexa < n) {
if(a[p] != '.' && p < strlen(a))
A[indexa++] = a[p];
else if(p >= strlen(a))
A[indexa++] = '0';
p++;
}
while(indexb < n) {
if(b[q] != '.' && q < strlen(b))
B[indexb++] = b[q];
else if(q >= strlen(b))
B[indexb++] = '0';
q++;
}
if(strcmp(A, B) == 0 && cnta == cntb)
printf("YES 0.%s*10^%d", A, cnta);
else
printf("NO 0.%s*10^%d 0.%s*10^%d" , A, cnta, B, cntb);
return 0;
}
10.5 A1022 Digital Library (30 分)
主要考察了map的使用以及string类型的输入输出。
scanf中加上\n提前把换行符读取掉,防止其干扰后续的getline函数的读取。
拆分关键词可以在读取的过程中,使用while(cin >> tkey),读完一个单词后再读一个字符,判断这个字符如果是换行符就break。
还可以利用strtok函数,对输入进行分割。
scanf("%d\n", &id);
getline(cin, ttitle);
while(cin >> tkey) {
key[tkey].insert(id);
char c = getchar();
if(c == '\n') break;
}
char* p;
const char* d = " ";
p = strtok(&keywords[0], d);
while(p)
{
string keyword(p);
keywordToid[keyword].insert(id);
p=strtok(NULL,d);
}