C++的STL库
一、vector动态数组
1、概述
动态数组,也就是不定长数组,数组的长度是可以根据我们的需要动态改变的。
在C++里面有已经写好的标准模板库 STL(Standard Template Library)库,实现了集合、映射表、栈、队列等数据结构和排序、查找等算法。我们可以很方便地调用标准库来减少我们的代码量。
C++ 中动态数组写作vector,而C语言中没有标准库,这也是为什么参加比赛推荐用 C++ 而不用C的原因。
尽量不要在比赛中使用指针!
2、构造
使用vector需要引入<vector>头文件、std命名空间
泛型T是我们数组要储存的数据类型,可以是 int、float、double、或者结构体等。初始的时候vector是空的。
#include "vector"
using namespace std;
int main() {
vector<int> vec;
return 0;
}3、使用
1)插入元素
push_back(T t):在尾部插入一个元素
int main() {
vector<int> vec;
vec.push_back(1); // 1
vec.push_back(2); // 1 2
vec.push_back(3); // 1 2 3
vec.push_back(4); // 1 2 3 4
return 0;
};2)获取长度与访问元素
size():获取长度
vec[index]:访问元素(类似数组,首位下标是0)
int main() {
vector<int> vec;
vec.push_back(1); // 1
vec.push_back(2); // 1 2
cout << vec.size() << endl; // 2
cout << vec[1] << endl; // 2
return 0;
};3)修改元素
直接赋值:vec[1] = 1
int main() {
vector<int> vec;
vec.push_back(1); // 1
cout << vec[0] << endl; // 1
vec[0] = 6;
cout << vec[0] << endl; // 6
return 0;
};4)删除元素
pop_back():删除最后一个元素
int main() {
vector<int> vec;
vec.push_back(1); // 1
vec.push_back(2); // 1 2
vec.pop_back(); // 1
return 0;
};5)清空
调用clear()方法就可以清空vector,但不释放内存
vector清空并清除内存的方法
vector<int>().swap(v);4、构造函数
我们在定义一个对象的时候可以给他赋予初始值。
第一个参数表示初始的动态数组的长度,第二个参数表示初始的数组里面每个元素的值。(如果不传入第二个参数,那么初始的值都是0。)
vector<int> vec(5,1); // 1 1 1 1 15、二维vector
二维动态数组:vector<vector<int> > vec2
<int> >中间有一个空格,这个空格一定要加上,否则在一些老版本的编译器上将不能通过编译。
因为每一维都是空的,我们必须要一维一维的赋值
vector 的维度可以像数组一样更多,但是超过两维以后操作起来会比较麻烦,所以一般用 vector 都只到两维。
vector<vector<int> > vec2;
for (int i = 0; i < 5; ++i) {
vector<int> temp(i + 1, 1);
vec2.push_back(temp);
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < vec2[i].size(); j++) {
cout << vec2[i][j];
}
cout << endl;
}
return 0;二、set集合
1、概述
集合是由一些不重复的数据组成的。
2、构造
使用set需要引入<set>头文件、std命名空间
泛型T是我们数组要储存的数据类型,可以是 int、float、double、或者结构体等。初始的时候map是空的。
#include "set"
using namespace std;
int main() {
set<int> s;
return 0;
}3、使用
1)插入元素
insert()方法向集合中插入一个新的元素。
如果集合中已经存在了某个元素,再次插入不会产生任何效果,集合中是不会出现重复元素的。
set<int> s;
s.insert(1); // 1
s.insert(2); // 1 2
s.insert(1); // 1 2
s.insert(3); // 1 2 32)删除元素
erase()方法删除集合中的一个元素
如果集合中不存在这个元素,不进行任何操作。
set<int> s;
s.insert(1); // 1
s.insert(2); // 1 2
s.erase(1); // 2
s.erase(3); // 23)判断元素存在
count()方法判断元素在set中出现的次数。
如果集合中存在我们要查找的元素,返回 1,否则会返回 0。
s.count(3);4)"增强for"遍历
在C++ 中遍历 set 是从小到大遍历的,也就是说 set 会帮我们排序的。
int main() {
set<int> s;
s.insert(1); // 1
s.insert(2); // 1 2
s.insert(1); // 1 2
s.insert(3); // 1 2 3
for (auto i: s) {
cout << i << endl;
}
return 0;
}5)迭代器遍历
C++通过迭代器可以访问集合中的每个元素,迭代器就好像指针指向set中的某个元素。通过操作这个指针,我们可以改变它指向的元素。
*(解引用运算符)操作可以获取迭代器指向的元素。++操作让迭代器指向下个元素,--操作让迭代器指向上一个元素。
迭代器的写法比较固定,set<T>::iterator it 就定义了一个指向set<T>这种集合的迭代器it,T是任意的数据类型,::iterator 是固定的写法。
begin()返回容器中起始元素的迭代器,end()返回容器的尾后迭代器
int main() {
set<int> s;
s.insert(1); // 1
s.insert(2); // 1 2
s.insert(1); // 1 2
s.insert(3); // 1 2 3
for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
cout << *it << endl;
}
return 0;
}6)反向遍历
rbegin()、rend()
int main() {
set<int> s;
s.insert(1); // 1
s.insert(2); // 1 2
s.insert(1); // 1 2
s.insert(3); // 1 2 3
for (set<int>::iterator it = s.rbegin(); it != s.rend(); it++) {
cout << *it << endl;
}
return 0;
}7)清空
clear()方法就可清空 set,同时会清空 set 占用的内存。
set<int> s;
s.clear();4、set和结构体
set 经常会配合结构体来使用,用set 来储存结构体和 vector 有些区别。正如我们前面所说的那样,set 是需要经过排序的。
系统自带的数据类型有默认的比较大小的规则,而我们自定义的结构体,系统是不可能知道这个结构体比较大小的方式的。
所以我们需要用一种方式来告诉系统怎么比较这个结构体的大小。其中一种方法叫做运算符重载,我们需要重新定义小于符号。
struct Node {
int x, y;
bool operator<(const Node &rhs) const {
if (x == rhs.x) {
return y < rhs.y;
} else {
return x < rhs.x;
}
}
};不要漏掉最后的
const。const函数表示不能对其数据成员进行修改操作,并且const对象不能调用非const成员函数,只允许调用const成员函数。
三、map映射
1、概述
关键字集合 (key)=> 值集合(value)
2、构造
使用map需要引入<map>头文件、std命名空间。
构造语句:map<T1,T2> m;
#include "map"
using namespace std;
int main() {
map<string,int> mp;
return 0;
}3、pair
insert()方法向集合中插入一个新的映射,參数是一个 pair
pair是一个标准库类型,定义在头文件utility中。可以看成是有两个成员变量 first 和second 的结构体,并且重载了<运算符(先比较 first 大小,如果一样再比较second )。当我们创建一个pair时,必须提供两个类型。
pair<string, int> p;make_pair(v1, v2)函数:返回由v1和v2初始化的pair,类型可以从v1 和v2的类型推断出来。我们向映射中加入新映射对的时候就是通过插入 pair 来实现的。若key已存在,本次插入无效。
4、使用
1)pair插入
若key已存在,本次插入无效。
int main() {
map<string,int> mp;
mp.insert(make_pair("wc",1));
mp.insert(make_pair("wmh",1));
mp.insert(make_pair("wmh",2)); // 无效插入
// {"wmh" -> 1, "wc" -> 1}
return 0;
}2)下标插入与修改
若key已存在,下标法能修改值(与make_pair不同)
int main() {
map<string,int> mp;
mp["wmh"] = 1;
mp["wc"] = 2;
mp["wc"] = 3;
// {"wmh" -> 1, "wc" -> 3}
return 0;
}3)判断映射存在
count(T t)方法判断元素在map中出现的次数。
如果集合中存在我们要查找的元素,返回 1,否则会返回 0。
s.count(3);4)访问映射
直接利用下标访问:mp["rexhao"]
而这里有一个比较神奇的地方:如果没有对"rexhao"做过映射的话,此时你访问mp["rexhao"],系统将会自动为"rexhao" 生成一个映射,其value为对应类型的默认值(比如int的默认值是 0, string 的默认值是空字符串)
访问映射前需要判断是否存在
int main() {
map<string, int> mp;
mp.insert(make_pair("wmh", 1));
if (mp.count("wmh")) {
cout << "wmh is in class " << mp["wmh"] << endl;
} else {
cout << "cannot find wmh" << endl;
}
if (mp.count("wc")) {
cout << "wc is in class " << mp["wc"] << endl;
} else {
cout << "cannot find wc" << endl;
}
return 0;
}5)迭代器遍历
遍历map是按照关键字(key)从小到大遍历的,这一点和set有些共性
for (map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) {
cout << it->first << " is in class " << it->second << endl;
}也可以使用auto类型
for (auto it = mp.begin(); it != mp.end(); it++) {
cout << it->first << " is in class " << it->second << endl;
}6)"增强for"遍历
for(auto it : mp){
cout << it.first <<" "<< it.second <<endl;
}5、二维map
1)map套用set
map套用set:map<int, set<string> > s;
- 插入:
s[2].insert("rexhao"); - 查询:
s[2].count("rexhao"); - 删除:
s[2].erase("rexhao");
2)map套用map
map套用map:map<int,map<string, int> > s;
- rexhao每来2班一次:
s[2]["rexhao"]++; - 查询rexhao来过2班的次数:
cout << s[2]["rexhao"] << endl;
二维的迭代器遍历
/**
* 二维 map 遍历
* @author 王铭颢
* @Date 2022/11/23 13:29
*/
#include "iostream"
#include "map"
using namespace std;
int main() {
/**
* int1:班级
* string:姓名
* int2:xxx来xx班的次数
*/
map<int, map<string, int> > mp;
// 数据初始化
mp[2]["wmh"] = 5;
mp[3]["wmh"] = 3;
mp[4]["wmh"] = 5;
mp[2]["wcc"] = 1;
for (map<int, map<string, int> >::iterator it = mp.begin(); it != mp.end(); it++) {
for (map<string, int>::iterator itt = it->second.begin(); itt != it->second.end(); itt++) {
cout << it->first << ":" << itt->first << ":" << itt->second << endl;
}
}
// 也可以使用auto类型
return 0;
}