在对STL进行详解之前, 我们先来了解一下怎么使用STL吧! 毕竟在算法竞赛和实际应用中, 我们更加关注使用, 而不是关注底层.

前言

遇事不决, 查标准文档

参考资料

 

正文

使用STL | 以map为例

C艹STL库官方文档 | map

首先我们进入官方文档, 可以看到如下页面

  • 请不要使用Chrome自带的翻译插件, 他只会让你更加看不懂;

  • 另, 实在不行可以去看CSDN等社区的阉割介绍, 但请注意甄别;

  • 又另, 这个世界上哪有意思准确的中文文档? 即便是国人自己开发的东西, 你说是吧, 尤雨溪?


想要使用一个STL, 首先要考虑如何实例化, 因此我们寻找构造函数map::map页面

C艹11为我们贴心的准备了5组构造函数, 而且下面有对应的解释

其中1最好理解, 构造一个空的map

map<char, int> demo1;   //demo1为空

2被称为范围构造, 也就是利用迭代器构造map, 例如通过vector构造map

vector<pair<int, string>> v;
v.push_back(pair<int, string>(1, "a"));
v.push_back(pair<int, string>(2, "b"));
v.push_back(pair<int, string>(3, "c"));
vector<pair<int, string>>::iterator begin = v.begin() + 1;
vector<pair<int, string>>::iterator end = v.end() -1;
map<int, string> demo2(begin, end);
//关于pair会在下文详解

3就是复制构造, 深拷贝一份map到新map

map<char, int> demo3_1;
map<char, int> demo3_2(demo3_1); //注意类型

4是新玩意儿, 移动构造, 其中&&被称为右值引用, 有空细说

5是初始化表构造, 类似于我们用int a[3]={1,2,3};定义数组, 我们也可以用类似的初始化表定义map

map<char, int> demo4={
{'A',1},
{'B',2},
{'C',3}
};
//有点像JSON...不像吗?

在文档的左边一列, 可以找到所有map类里面定义的成员函数, 以map::at为例, 进去之后, 我们直奔第一句话

这句话的意思是map::at返回一个键为k的值的引用;

再往上看, 上面的绿字提供了map::at函数签名:

mapped_type& at (const key_type& k);
const mapped_type& at (const key_type& k) const;

当然, 下面提供了实例

// map::at
#include <iostream>
#include <string>
#include <map>

int main ()
{
std::map<std::string,int> mymap = {
{ "alpha", 0 },
{ "beta", 0 },
{ "gamma", 0 } };

mymap.at("alpha") = 10;
mymap.at("beta") = 20;
mymap.at("gamma") = 30;

for (auto& x: mymap) {
std::cout << x.first << ": " << x.second << '\n';
}

return 0;
}
/*
输出结果:
alpha: 10
beta: 20
gamma: 30
*/

由行13-15可以知道, map::at可以用来对某个键值对进行赋值操作;

行17的写法是C艹11中引入的新的写法, 能更快捷(主要指敲代码时)的遍历某个容器.

这样, 我们就掌握了STL某个函数的具体用法了, 是不是很方便快捷呐!?

别急, 对于上面的程序段, 其实还有一个小问题没有回答, 那就是行18的firstsecond成员变量是哪里来的, 在官方文档map栏目里面并没有这个成员变量, 类比数组的遍历是整型(的引用), 我们猜想, 这两个成员变量是x的, 但是, 我们用auto&自动声明了x的类型, 因此我们不知道x的具体类型.

这时, 我们可以用VSCode查看类型(这么不专业吗啊喂!)

原来map的遍历, 也就是map中元素的类型, 是pair模板的一个实例化. 继续在文档中搜索pair

果然, pair是一个结构体模板, firstsecond都是他的成员变量.

至此, 我们对文档的使用和STL的结构和用法有了更深层次的理解.

 

常用STL随手记

string类

C艹STL库官方文档 | string类

#include<string>
#include<iostream>
using namespace std;

void print(string str, int begin, int end){
for(int i=begin; i<=end; ++i) cout<<str.at(i);
cout<<endl;
}

int main(){
//初始化
string str1;
str1 = "Vanadium";
cout<<"str1 = "<<str1<<endl;
string str2(6,'6');
cout<<"str2 = "<<str2<<endl;
string str3;
str3 = 'K';
cout<<"str3 = "<<str3<<endl;

//长度
cout<<"length of str1 = "<<str1.length()<<endl;

//赋值和复制
string str4; str4 = str2;
cout<<"str4 = "<<str4<<endl;

str4.assign(str1, 2, 4); //从第2个开始, 复制4个字符
cout<<"str4 = "<<str4<<endl;

str1[0] = 'v'; //str1.at(0) = 'v'
cout<<"str1 = "<<str1<<endl;

//连接

str1 += str2;
cout<<"str1 = "<<str1<<endl;

str1 = "vanadium";
str1.append(str2, 3, 6); //从第3个开始, 复制6个字符, 但不会超过原串长度
cout<<"str1 = "<<str1<<endl;

//比较
bool b1 = str1 < str4;
cout<<"str1 = "<<str1<<endl;
cout<<"str4 = "<<str4<<endl;
cout<<"str1 < str4 = "<<b1<<endl;

bool b2 = str4.compare(0, 2, str1, 1, 5); //str4[0:3] > str1[1:6]
cout<<"str4[0:3] = "; print(str4, 0, 2);
cout<<"str1[1:6] = "; print(str1, 1, 5);
cout<<"str4.compare(0, 2, str1, 1, 5) = "<<b2<<endl;

//字串
cout<<"str1 = "<<str1<<endl;
cout<<"str1[4:11] = "<<str1.substr(4, 6)<<endl; //从第4个开始, 取6个字符

//交换
cout<<"str1 = "<<str1<<endl;
cout<<"str4 = "<<str4<<endl;
str1.swap(str4);
cout<<"str1 = "<<str1<<endl;
cout<<"str4 = "<<str4<<endl;

//查找
cout<<"first a in str4 = "<<str4.find('a')<<endl;
cout<<"last a in str4 = "<<str4.rfind('a')<<endl;

//删除
cout<<"str4 = "<<str4<<endl;
str4.erase(3); //删除3及之后的所有字符
cout<<"str4 = "<<str4<<endl;
cout<<"str4 = "<<str4.length()<<endl;
cout<<"str4 = "<<str4.size()<<endl;

//替换
str4 = "Vanadium's Blog";
cout<<str4<<endl;
cout<<str4.replace(11,4,"Cabin")<<endl;
cout<<str4.replace(11,5,"Cabin",0,3)<<endl;

//插入
str4 = "Vanadium's Blog";
cout<<str4<<endl;
cout<<str4.insert(10,"Wonderful")<<endl;
str4 = "Vanadium's Blog";
cout<<str4<<endl;
cout<<str4.insert(10,"Wonderful",0,6)<<endl;
}

容器与迭代器

//声明迭代器
vector<int>::iterator i;
vector<int>::const iterator i;

//解引用迭代器
cout<<*i<<endl;
容器 支持的迭代器
vector 随机访问
deque 随机访问
list 双向
set/multiset 双向
map/multimap 双向
stack 不支持
queue 不支持
priority_queue 不支持

P.S.笔者认为随机访问迭代器Random access iterator应该翻译成随意访问迭代器更加合理,因为随机访问迭代器支持随意的访问容器中的任一元素

关于迭代器的细分将会在之后讲到,现在可以先粗浅的认识迭代器

图源: Github | PPT | Back to Basics: Classic STL - Bob Steagall - CppCon 2021

vector类

C艹STL库官方文档 | vector类

#include<iostream>
#include<vector>
using namespace std;

int main(){
//声明
vector<int> vec;
vector<int> vec_1({1,2,3,4});
vector<int> vec_2={1,2,3,4};

//插入
vec.push_back(1);
vec.push_back(4); vec.push_back(3); vec.push_back(5); vec.push_back(2);

//遍历
for(auto& item:vec) cout<<item<<' ';
cout<<endl;

vector<int>::iterator i;
for(i=vec.begin();i!=vec.end();++i) cout<<*i<<' '; //建议统一使用!=作为边界
cout<<endl;
}

此外,参照string类,vector类有很多类似的用法

pair类

C艹STL库官方文档 | pair类