STL
vector
基础知识
- #include < vector>
- using std::vector;
- vector< T> v;//定义空的动态数组
- vector< T> v(num, value); //定义一个长度为num,每一个元素初值都是value的动态数组
- v.push_back(value);//插入value
- v.pop_back(); //删除一个元素
- v.clear(); 清空动态数组
- v.size();返回动态数组的长度
- vector< vector< int > > vec;//定义二维的动态数组
- vector<vector< int> > vec(n, vector< int>(m, 0)); //二维动态数组定义并初始化为全0
练手
-
打印乘法表
#include <iostream> #include <vector> using namespace std; int main() { vector<vector<int> > v2d; for (int i = 0; i < 5; i++) { v2d.push_back(vector<int>()); } for (int i = 0; i < v2d.size(); i++) { for (int j = 0; j <= i; j++) { v2d[i].push_back((i + 1) * (j + 1)); } } for (int i = 0; i < v2d.size(); i++) { for (int j = 0; j < v2d[i].size(); j++) { cout << i + 1 << " * " << j + 1 << " = " << v2d[i][j] << "\t"; } cout << endl; } return 0; } /* 1 * 1 = 1 2 * 1 = 2 2 * 2 = 4 3 * 1 = 3 3 * 2 = 6 3 * 3 = 9 4 * 1 = 4 4 * 2 = 8 4 * 3 = 12 4 * 4 = 16 5 * 1 = 5 5 * 2 = 10 5 * 3 = 15 5 * 4 = 20 5 * 5 = 25 */
set
知识
- #include < set>
- using namespace std::set;
- 集合中的元素要求互异性。
- 插入元素用insert(),如果集合中已经存在了某个元素,再次插入不会产生任何效果。
- 判断某个元素是否在集合里,可以用count()函数,存在返回1,否则返回0。
- 遍历要用迭代器。通过* 解引用可以获取迭代器指向的元素。set< T>::iterator it;
- erase();可以删除元素
- clear()可以清空set,而且会清空内存。
- set中插入、删除、查找时间复杂度都是 O ( l o g n ) O(log n) O(logn),且内部元素是有序的。但自定义的结构体,需要自行重载<运算符。
练手
#include <iostream>
#include <set>
using namespace std;
struct Point
{
int x, y;
bool operator<(const Point &rhs) const
{ //rhs:right hand side右操作数
//后面这个const表示不能对其数据成员进行修改,并且const对象只能调用const成员函数
if (x == rhs.x)
{
return y < rhs.y;
}
return x < rhs.x;
}
};
int main()
{
int n;
set<Point> v;
cin >> n;
for (int i = 0; i < n; i++)
{
Point temp;
cin >> temp.x >> temp.y;
v.insert(temp);
}
for (set<Point>::iterator it = v.begin(); it != v.end(); it++)
{
cout << it->x << " " << it->y << endl;
}
return 0;
}
/*
输入:
6
5 6
5 2
2 1
3 4
1 2
1 1
输出:
1 1
1 2
2 1
3 4
5 2
5 6
*/
map
知识
-
map是映射,通过key可以找value
-
insert()函数向集合中插入新的映射,参数是一个pair
-
pair: 在头文件utility中,可以看作两个成员变量first和second的结构体,重载了<运算符,先比较first,再比较second。
pair<string, int> p;
-
make_pair(v1, v2)函数返回由v1和v2初始化的pair,类型可以从v1和v2的类型推断出来。
-
插入时,如果插入的key之前已经存在,将不会用插入的新的value替代原来的value,插入无效。
-
访问映射和数组一样,用[]就能访问。如果没有对[]里的key做过映射的话,系统会自动生成一个映射,value是对应类型的默认值。insert无法完成更改,但[]可以给映射赋予新的值。但有时我们不希望自动生成映射,就需要用count()函数进行判断是否已有映射。
-
map<T1, T2>::iterator it可以定义一个迭代器。迭代器指向的是一个pair,有first和second。
it -> first 和 (*it).first效果是一样的。
-
遍历map是按照关键字从小到大遍历的,和set类似。
-
clear()可清空map和其占用的内存。
-
map的insert()和count都是O(log n)的,size()获取映射对个数是O(1)的,clear()是O(n)的。
练手
-
嵌套,两层的时候,遍历定义的两个迭代器
#include <iostream> #include <string> #include <map> using namespace std; int main() { map<int, map<string, int> > info; int n; cin >> n; for (int i = 0; i < n; i++) { int class_id; string name; cin >> class_id >> name; info[class_id][name]++; } for (map<int, map<string, int> >::iterator it = info.begin(); it != info.end(); it++) { for (map<string, int>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) { cout << "There are " << it2->second << " people named " << it2->first << " in class " << it->first << endl; } } return 0; } /* 输入: 6 1 zgh 2 yuhaoran 2 yuhaoran 1 party 100 xxxx 50 xxxx 输出: There are 1 people named party in class 1 There are 1 people named zgh in class 1 There are 2 people named yuhaoran in class 2 There are 1 people named xxxx in class 50 There are 1 people named xxxx in class 100 */
-
锯齿矩阵:每一行元素个数不相同的矩阵,现在在某些行的末尾插入某些元素。
#include <iostream> #include <vector> using namespace std; vector<int> mat[10005]; int main() { int n, m, x, y; cin >> n >> m; for (int i = 0; i < m; i++) { cin >> x >> y; mat[x].push_back(y); } for (int i = 1; i <= n; i++) { for (int j = 0; j < mat[i].size(); j++) { if (j != mat[i].size() - 1) { cout << mat[i][j] << " "; }else { cout << mat[i][j] << endl; } } if (mat[i].size() == 0) cout << endl; } return 0; } /* 输入: 3 12 1 3 2 2 2 3 2 4 3 1 3 6 1 5 1 2 1 6 3 2 3 7 1 1 输出: 3 5 2 6 1 2 3 4 1 6 2 7 */
-
对比两个结构体是否相同,样本库应该是互不相同的,用set
#include <iostream> #include <set> using namespace std; struct people { int h; int w; int age; people(int _h, int _w, int _age) { h = _h; w = _w; age = _age; } bool operator<(const people &rhs) const { if(h != rhs.h) return h < rhs.h; if (w != rhs.w) return w < rhs.w; return age < rhs.age; } }; set<people> s; int main() { int n, m, h, w, age; cin >> n >> m; for (int i = 0; i < n; i++) { cin >> h >> w >> age; s.insert(people(h, w, age)); } for (int i = 0; i < m; i++) { cin >> h >> w >> age; if (s.count(people(h, w, age))) { cout << "yes" << endl; } else { cout << "no" << endl; } } return 0; } /* 输入: 3 2 166 50 30 178 60 23 132 40 15 167 50 30 178 60 23 输出: yes */
-
输出不同书籍的数量,按照字典序。显然可以用map,map本身就是排好序的。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <map> #include <string> #include <cstdio> //10^5以上的输入就要用scanf using namespace std; map<string, int> mp; char name[105]; int main() { int n; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%s", name); //string类型不能直接scanf %s,但可以用c_str()转为c字符串;但机制很奇怪,很容易出错,所以用scanf就用char数组 mp[name]++; //map用[]访问,如果没有初始化为默认值 } printf("%d\n", mp.size()); for (map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) { printf("%s %d\n", (it->first).c_str(), it->second); } return 0; } /* 4 English Math Chinese Chinese 3 Chinese 2 English 1 Math 1 */
-
移动积木,本来n个位置上分别放着编号1-n的积木,然后进行m次操作a,b,每次将b的积木整体移动到a上。如果a,b相等,则不移动。
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <vector> using namespace std; vector<int> v[10005]; int main() { int n, m, a, b; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { v[i].push_back(i); } for (int i = 0; i < m; i++) { scanf("%d%d", &a, &b); if (a == b) continue; for (int j = 0; j < v[b].size(); j++) { v[a].push_back(v[b][j]); } vector<int>().swap(v[b]); } for (int i = 1; i <= n; i++) { for (int j = 0; j < v[i].size(); j++) { if (j != v[i].size()-1) { printf("%d ", v[i][j]); } else { printf("%d", v[i][j]); } } printf("\n"); } return 0; } /* 输入: 4 4 3 1 4 3 2 4 2 2 输出: 2 4 3 1 */
-
求两个集合的并集。
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <set> using namespace std; set<int> s; int main() { int n, m, x, cnt = 0; scanf("%d%d", &n, &m); for(int i = 0; i < n + m; i++) { scanf("%d", &x); s.insert(x); } for(set<int>::iterator it = s.begin(); it != s.end(); it++) { if (cnt != s.size() - 1) { printf("%d ", (*it)); cnt++; } else { printf("%d\n", (*it)); } } return 0; } /* 输入: 1 2 1 2 3 输出: 1 2 3 */
-
输入n:表示事件数;n行整数d和单词word:d=0表示记住该单词,d=1表示询问是否认识该单词。(大小写等价)\
#include <cstdio> #include <set> #include <string> #include <iostream> using namespace std; set<string> s; string ss; int main() { int n, op; cin >> n; for (int i = 0; i < n; i++) { cin >> op >> ss; for (int j = 0; j < ss.size(); j++) { if(ss[j] >= 'A' && ss[j] <= 'Z') { ss[j] = 'a' + (ss[j] - 'A'); } } if (op == 0) { s.insert(ss); } else { if (s.count(ss)) { cout << "Yes" << endl; } else { cout << "No" << endl; } } } return 0; } /* 输入: 4 1 jisuanke 0 Jisuanke 0 JISUANKE 1 JiSuanKe 输出: No Yes */
-
输出出现次数最多的数和出现的次数。如果有多个最大次数的数,输出值最大的那个。
#include <iostream> #include <string> #include <map> using namespace std; map<string, map<string, int > > mp; string s1, s2; int d; int main() { int n; cin >> n; for (int i = 0; i < n; i++) { cin >> s1 >> s2 >> d; mp[s2][s1] += d; } for (map<string, map<string, int> >::iterator it1 = mp.begin(); it1 != mp.end(); it1++) { cout << (it1->first) << endl; for(map<string, int>::iterator it2 = (it1->second).begin(); it2 != (it1->second).end(); it2++) { cout << " |----" << (it2->first) << "(" << (it2->second) << ")" << endl; } } return 0; } /* 输入: 5 apple shandong 3 pineapple guangdong 1 sugarcane guangdong 1 pineapple guangdong 3 pineapple guangdong 1 输出: guangdong |----pineapple(5) |----sugarcane(1) shandong |----apple(3) */