在对STL进行详解之前, 我们先来了解一下怎么使用STL吧! 毕竟在算法竞赛和实际应用中, 我们更加关注使用, 而不是关注底层.
前言
遇事不决, 查标准文档
参考资料
正文
使用STL | 以map为例
C艹STL库官方文档 | map
首先我们进入官方文档, 可以看到如下页面
-
请不要使用Chrome自带的翻译插件, 他只会让你更加看不懂;
-
另, 实在不行可以去看CSDN等社区的阉割介绍, 但请注意甄别;
-
又另, 这个世界上哪有意思准确的中文文档? 即便是国人自己开发的东西, 你说是吧, 尤雨溪?
想要使用一个STL, 首先要考虑如何实例化, 因此我们寻找构造函数map::map
页面
C艹11为我们贴心的准备了5组构造函数, 而且下面有对应的解释
其中1最好理解, 构造一个空的map
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);
|
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} };
|
在文档的左边一列, 可以找到所有map类里面定义的成员函数, 以map::at
为例, 进去之后, 我们直奔第一句话
这句话的意思是map::at
返回一个键为k
的值的引用;
再往上看, 上面的绿字提供了map::at
的函数签名:
mapped_type& at (const key_type& k); const mapped_type& at (const key_type& k) const;
|
当然, 下面提供了实例
#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; }
|
由行13-15可以知道, map::at
可以用来对某个键值对进行赋值操作;
行17的写法是C艹11中引入的新的写法, 能更快捷(主要指敲代码时)的遍历某个容器.
这样, 我们就掌握了STL某个函数的具体用法了, 是不是很方便快捷呐!?
别急, 对于上面的程序段, 其实还有一个小问题没有回答, 那就是行18的first
和second
成员变量是哪里来的, 在官方文档map栏目里面并没有这个成员变量, 类比数组的遍历是整型(的引用), 我们猜想, 这两个成员变量是x的, 但是, 我们用auto&
自动声明了x的类型, 因此我们不知道x的具体类型.
这时, 我们可以用VSCode查看类型(这么不专业吗啊喂!)
原来map的遍历, 也就是map中元素的类型, 是pair模板的一个实例化. 继续在文档中搜索pair
果然, pair
是一个结构体模板, first
和second
都是他的成员变量.
至此, 我们对文档的使用和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); cout<<"str4 = "<<str4<<endl;
str1[0] = 'v'; cout<<"str1 = "<<str1<<endl;
str1 += str2; cout<<"str1 = "<<str1<<endl;
str1 = "vanadium"; str1.append(str2, 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); 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;
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); 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类