什么是STL?
大佬:为什么C++比C更受人欢迎呢?除了C++ 的编译令人感到更舒适,C++的标准模板库(STL)也占了很重要的原因。当你还在用手手写快排、手写二叉堆,挑了半天挑不出毛病的时候,C++党一手STL轻松AC,想不嫉妒都难。
萌新:STL太酷了吧,快跟我讲讲具体是什么玩意吧!
大佬:STL(Standard Template Library,标准模板库),是惠普实验室开发的一系列软件的统称。现在主要出现在 c++中,但是在引入 c++之前该技术已经存在很长时间了。STL 从广义上分为: 容器(container) 算法(algorithm) 迭代器(iterator),容器和算法之间通过迭代器进行无缝连接。STL 几乎所有的代码都采用了模板类或者模板函数,这相比传统的由函数和类组成的库来说提供了更好的代码重用机会。
萌新:蛤??????说了这么多!还是不知道STL是个啥呀!
大佬:别着急,上面那是百度文库的东西,你不用理会哈~我们一步步走着瞧,来开启学习STL的大门吧!
萌新:大佬NB!
STL容器有哪些呢?
大佬:STL容器太多了,我可不能讲完,要讲的太细,我们做算法不用,理解起来也十分困难,我就来和你聊聊最常用的STL库中的几个容器吧: vector(动态数组), queue(队列), stack(栈) , string(字符串) , set(集合),map(映射容器)!
萌新:感谢大佬理解!
浅谈C++ STL vector 容器
大佬:你知道vector的中文是啥意思嘛?
萌新:emmm,是矢量的意思吧!
大佬:NONONO! vector和高中物理、几何等东西没有任何关系。它在计算机里就叫做:动态数组!我们知道,一个数组必须要有固定的长度,在开一个数组的时候,这个长度也就被静态地确定下来了。但是vector却是数组的“加强版”,对于一组数据来讲,你往vector里存多少数据,vector的长度就有多大。也就是说,我们可以将其理解为一个“变长数组”。
萌新:原来如此!!
大佬:
接下来细细讲讲vector用法:
vector容器的声明:
vector容器存放在模板库:#include<vector>
里,使用前需要先开这个库。
vector容器的声明遵循C++STL的一般声明原则:
容器类型<变量类型> 名称
例:
#include<vector>
vector<int> vec;
vector<char> vec;
vector<pair<int,int> > vec;
vector<node> vec;
struct node{...};
vector容器的使用方法:
vector容器的使用方法大致如下表所示:
用法 | 作用 |
---|---|
vec.begin(),vec.end() | 返回vector的首、尾迭代器 |
vec.front(),vec.back() | 返回vector的首、尾元素 |
vec.push_back() | 从vector末尾加入一个元素 |
vec.size() | 返回vector当前的长度(大小) |
vec.pop_back() | 从vector末尾删除一个元素 |
vec.empty() | 返回vector是否为空,1为空、0不为空 |
vec.clear() | 清空vector |
除了上面说过的那些之外,我们的vector容器是支持随机访问的,即可以像数组一样用[][]来取值。请记住,不是所有的STL容器都有这个性质!在STL的学习过程中,一定要清楚各个容器之间的异同!
萌新:emmm看了这么多!有没有什么具体的,能实际操作的东西让我们练练手呢?我想自己试试!
大佬:来吧!给你题目了哦!
萌新:这也太简单了吧!嘿嘿嘿!
大佬:好!那就继续咯~
浅谈C++ STL queue 容器
大佬:queue在英文中是队列的意思。队列是一种基本的数据结构。而C++STL中的队列就是把这种数据结构模板化了。我们可以在脑中想象买票时人们站的排队队列。我们发现,在一个队列中,只可以从队首离开,从队尾进来(没有插队,想啥呢)。即一个先进先出的数据结构。
上图理解:
萌新:这不so easy嘛!快点快点!我想一口吃个大胖子!!
大佬:嘿嘿!鸡汤来喽!
queue容器的声明
queue容器存放在模板库:#include<queue>
里,使用前需要先开这个库。
queue容器的声明遵循C++STL的一般声明原则:
容器类型<变量类型> 名称
例:
#include<queue>
queue<int> q;
queue<char> q;
queue<node> q;
struct node{...};
queue容器的使用方法
queue容器的使用方法大致如下表所示:
用法 | 作用 |
---|---|
q.front(),q.back() | 返回queue的首、尾元素 |
q.push() | 从queue末尾加入一个元素 |
q.size() | 返回queue当前的长度(大小) |
q.pop() | 从queue末尾删除一个元素 |
q.empty() | 返回queue是否为空,1为空、0不为空 |
注意,虽然vector和queue是两种最基本的STL容器,但请记住它们两个不是完全一样的。就从使用方法来讲:
queue不支持随机访问,即不能像数组一样地任意取值。并且,queue并不支持全部的vector的内置函数。比如queue不可以用clear()函数清空,清空queue必须一个一个弹出。同样,queue也并不支持遍历,无论是数组型遍历还是迭代器型遍历统统不支持,所以没有begin(),end();函数,使用的时候一定要清楚异同!
萌新:噢噢!这里还有这么多小细节呀!好的好的,我会记住的!
浅谈C++ STL stack 容器
大佬:stack在英文中是栈的意思。栈是一种基本的数据结构。而C++STL中的栈就是把这种数据结构模板化了。
栈的示意图如下:这是一个先进后出的数据结构。这非常重要!!
事实上,stack容器并不是一种标准的数据结构,它其实是一个容器适配器,里面还可以存其他的STL容器。但那种使用方法过于高深而且不是很常用,所以在此不与介绍。请有兴趣的小萌新们可以自行查询资料。
萌新:呼呼!学了这么多!看似很简单,但是记忆的东西还是好多啊!头有点晕晕的!能不能缓缓啊!
大佬:哈?这就不行了?告诉你呀!能靠记忆解决的东西是最简单的!到这里就放弃了,你可就太逊了哦!赶快打起精神来,复习复习前面两个容器,我们接着继续!
萌新:竟然说我菜!啊!气死了!不行,我得学给你看!来吧!
大佬:嘿嘿!鸡汤来喽!
stack容器的声明
stack容器存放在模板库:#include<stack>
里,使用前需要先开这个库。
stack容器的声明遵循C++STL的一般声明原则:
容器类型<变量类型> 名称
例:
#include<stack>
stack<int> st;
stack<char> st;
stack<pair<int,int> > st;
stack<node> st;
struct node{...};
stack容器的使用方法
stack容器的使用方法大致如下表所示:
用法 | 作用 |
---|---|
st.top() | 返回stack的栈顶元素 |
st.push() | 从stack栈顶加入一个元素 |
st.size() | 返回stack当前的长度(大小) |
st.pop() | 从stack栈顶弹出一个元素 |
st.empty() | 返回stack是否为空,1为空、0不为空 |
浅谈C++ STL string容器
萌新:呜呜呜< _ >怎么这么多!
大佬:别着急这才哪跟哪,谁跟谁呢!来来,继续"喝",别停哦!
萌新:我尽量
大佬:其实string并不是STL的一种容器,但是由于它的使用方法等等和STL容器很像,所以就把它当作STL容器一样介绍。
其实string容器就是个字符串,这通过它的英文译名就能看得出来。但是对于字符串以及字符串的相关操作,可能读者还是对普通的C/C++的#include<cstring>
,#include<string.h>
库更熟悉一些。我丝毫不否认这些传统字符操作的经典性和实用性,但是由于它们函数定义的局限,有些时候对于一些特殊的读入、输出、遍历等要求,它的操作并不如string容器好用。
比如,要求读入一群中间可能带空格的字符串,如果用传统方式进行读入,可能就会很麻烦,但是如果使用string的话,一个读入函数就可以完全搞定。
string容器的使用方法及与传统字符读入的对比
一张图解决问题。
详解C++ STL set 容器
大佬:我知道你要抱怨了,停下你的抱怨哦,这下乖乖听我讲课!好好听才能学好!知道了不!
萌新:看来还是你懂我呀!我会加油的!
大佬:不罗嗦了!直接来干货!
set容器的概念和性质
set在英文中的意义是:集合。set容器也的确“人如其名”,实现了这个集合的功用。
高中数学必修一集合那章(高一以下的小伙伴不用慌,不讲数学只讲概念),关于集合的性质,给出了三个概念:无序性、互异性、确定性。
那么,set容器的功用就是维护一个集合,其中的元素满足互异性。
我们可以将其理解为一个数组。这个数组的元素是两两不同的。
这个两两不同是指,如果这个set容器中已经包含了一个元素i,那么无论我们后续再往里假如多少个i,这个set中还是只有一个元素ii,而不会出现一堆i的情况。这就为我们提供了很多方便。
set容器的声明
set容器的声明和大部分C++STL容器一样,都是:容器名<变量类型> 名称的结构。前提需要开#include库。如:
#include<set>
set<int> s;
set<char> s;
set<pair<int,int> > s;
set<node> s;
struct node{...};
set容器的使用
其实,C++STL容器的使用方式都是差不多的。我们完全可以举一反三地去类比。
s.empty();
empty()函数返回当前集合是否为空,是返回1,否则返回0.
s.size();
size()函数返回当前集合的元素个数。
s.clear();
clear()函数清空当前集合。
s.begin(),s.end();
begin()函数和end()函数返回集合的首尾迭代器。注意是迭代器。我们可以把迭代器理解为数组的下标。但其实迭代器是一种指针。这里需要注意的是,由于计算机区间**“前闭后开”**的结构,begin()函数返回的指针指向的的确是集合的第一个元素。但end(返回的指针却指向了集合最后一个元素后面一个元素。
s.insert(k);
insert(k)函数表示向集合中加入元素k。
s.erase(k);
erase(k)函数表示删除集合中元素k。这也反映了set容器的强大之处,指哪打哪,说删谁就删谁,完全省略了遍历、查找、复制、还原等繁琐操作。更不用像链表那种数据结构那么毒瘤。直接一个函数,用O(logn)的复杂度解决问题。
s.find(k);
find(k)函数返回集合中指向元素k的迭代器。如果不存在这个元素,就返回s.end(),这个性质可以用来判断集合中有没有这个元素。
详解C++ STL map 容器
大佬:好了好了!最后一个知识点了!马上搞定了哦!别着急!
萌新:其实吧,学了这么多!我还越学越上头!再来再来!
大佬: 好!那废话就不多说了!直接进入核心!
map容器的概念
map的英语释义是“地图”,但map容器可和地图没什么关系。map是**“映射容器”**,其存储的两个变量构成了一个键值到元素的映射关系。
比如下图:
我们可以根据键值快速地找到这个映射出的数据。
map容器的内部实现是一棵红黑树(平衡树的一种),因为比较复杂而且与理解并无多大关系,所以不予介绍,有兴趣的小萌新可以自己查阅相关的资料。
map容器的声明
map容器存在于STL模板库#include<map>
中。使用的时候需要先开这个库。
比如:
#include<map>
map<int,char> mp;
这就建立了一个从一个整型变量到一个字符型变量的映射。
map容器的用法
1.常规操作
如其他C++STL容器一样,map支持基本相同的基本操作:
比如清空操作,函数clear(),返回容器大小size(),返回首尾迭代器begin(),end()等。
2.插入操作
map容器的插入操作一种是类似于数组类型,可以把键值作为数组下标对map进行直接赋值:
mp[1]='a';
3.删除操作
可以直接用erase()函数进行删除,如:
mp.erase('b');
4.遍历操作
和其他容器差不多,map也是使用迭代器实现遍历的。如果我们要在遍历的时候查询键值(即前面的那个),可以用it->first
来查询,那么,当然也可以用it->second
查询对应值(后面那个)
5.查找操作
查找操作类比set的查找操作。但是map中查找的都是键值。
比如:
mp.find(1);
即查找键值为1的元素。
萌新:太好了!终于学完了!呼呼快让我休息一会吧!
大佬:现在正是成热打铁的时候,一定别忘记课后复习呀!!!
萌新:收到!要想变强!就得吃苦!我去复习了大佬!冲!
mp[1]='a';
3.删除操作
可以直接用erase()函数进行删除,如:
mp.erase('b');
4.遍历操作
和其他容器差不多,map也是使用迭代器实现遍历的。如果我们要在遍历的时候查询键值(即前面的那个),可以用it->first
来查询,那么,当然也可以用it->second
查询对应值(后面那个)
5.查找操作
查找操作类比set的查找操作。但是map中查找的都是键值。
比如:
mp.find(1);
即查找键值为1的元素。
萌新:太好了!终于学完了!呼呼快让我休息一会吧![外链图片转存中…(img-GpCvdVCd-1646987505961)]
大佬:现在正是成热打铁的时候,一定别忘记课后复习呀!!!
萌新:收到!要想变强!就得吃苦!我去复习了大佬!冲!