C++ STL 容器基本使用详解:

史上最全的C++ STL 容器大礼包

为什么C++比C更受人欢迎呢?除了C++ 的编译令人感到更舒适,C++的标准模板库(STL)也占了很重要的原因。当你还在用手手写快排、手写二叉堆,挑了半天挑不出毛病的时候,C++党一手STLSTL轻松AC,想不嫉妒都难。
所以这篇随笔就带大家走进博大精深的C++STL,系统讲解各种STL容器及其用法、作用。在学习STL的时候认真体会STL语法及功能,提升自己在算法竞赛及程序设计中解题、码代码的能力。

  • vector容器
  • queue 容器
  • stack 容器
  • string容器
  • priority_queue 容器
  • deque 容器
  • set 容器
  • multiset 容器
  • bitset 容器
  • map 容器

C++ STL vector 容器

vector容器的概念
vector在英文中是矢量的意思。
我们知道,一个数组必须要有固定的长度,在开一个数组的时候,这个长度也就被静态地确定下来了。但是vector却是数组的“加强版”,对于一组数据来讲,你往vector里存多少数据,vector的长度就有多大。也就是说,我们可以将其理解为一个“变长数组”。

事实上,vector的实现方式是基于倍增思想的:假如vector的实际长度为n,m为vector当前的最大长度,那么在加入一个元素的时候,先看一下,假如当前的n=m,则再动态申请一个2m大小的内存。反之,在删除的时候,如果n≥m2,则再释放一半的内存。

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的学习过程中,一定要清楚各个容器之间的异同!

C++ STL queue 容器

queue容器的概念
queue在英文中是队列的意思。队列是一种基本的数据结构。而C++STL中的队列就是把这种数据结构模板化了。我们可以在脑中想象买票时人们站的排队队列。我们发现,在一个队列中,只可以从队首离开,从队尾进来(没有插队,想啥呢)。即一个先进先出的数据结构。

上图理解:
在这里插入图片描述

queue容器的声明
queue容器存放在模板库:#include <queue>里,使用前需要先开这个库。

queue容器的声明遵循C++STL的一般声明原则:

容器类型<变量类型> 名称

例:

#include<queue>

queue<int> q;

queue<char> q;

queue<pair<int,int> > 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容器的概念
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容器

本篇随笔简单讲解一下C++STL中string容器的使用方法及技巧。

string容器的概念
其实string并不是STL的一种容器,但是由于它的使用方法等等和STL容器很像,所以就把它当作STL容器一样介绍。

其实string容器就是个字符串,这通过它的英文译名就能看得出来。但是对于字符串以及字符串的相关操作,可能读者还是对普通的C/C++的#include<cstring>#include<string.h>库更熟悉一些。我丝毫不否认这些传统字符操作的经典性和实用性,但是由于它们函数定义的局限,有些时候对于一些特殊的读入、输出、遍历等要求,它的操作并不如string容器好用。

比如,要求读入一群中间可能带空格的字符串,如果用传统方式进行读入,可能就会很麻烦,但是如果使用string的话,一个读入函数就可以完全搞定。

string容器的使用方法及与传统字符读入的对比:
在这里插入图片描述

C++ STL priority_queue 容器

priority_queue容器的概念
priorityqueue在英文中是优先队列的意思。

队列是一种基本的数据结构。其实现的基本示意图如下所示:

在这里插入图片描述

而C++STL中的优先队列就是在这个队列的基础上,把其中的元素加以排序。其内部实现是一个二叉堆。所以优先队列其实就是把堆模板化,将所有入队的元素排成具有单调性的一队,方便我们调用。

priority_queue容器的声明
priorityqueue容器存放在模板库:#include<queue>里,使用前需要先开这个库。

这里需要注意的是,优先队列的声明与一般STL模板的声明方式并不一样。事实上,我认为其是C++STL中最难声明的一个容器。

大根堆声明方式:
大根堆就是把大的元素放在堆顶的堆。优先队列默认实现的就是大根堆,所以大根堆的声明不需要任何花花肠子,直接按C++STL的声明规则声明即可。

#include<queue>
priority_queue<int> q;
priority_queue<string> q;
priority_queue<pair<int,int> > q;

C++中的int,string等类型可以直接比较大小,所以不用我们多操心,优先队列自然会帮我们实现。但是如果是我们自己定义的结构体,就需要进行重载运算符了,有需要者自行百度。

小根堆声明方式
大根堆是把大的元素放堆顶,小根堆就是把小的元素放到堆顶。

实现小根堆有两种方式:

第一种是比较巧妙的,因为优先队列默认实现的是大根堆,所以我们可以把元素取反放进去,因为负数的绝对值越小越大,那么绝对值较小的元素就会被放在前面,我们在取出的时候再取个反,就瞒天过海地用大根堆实现了小根堆。

第二种:

小根堆有自己的声明方式,我们记住即可(我也说不明白道理):

priority_queue<int,vector<int>,greater<int> >q;

注意,当我们声明的时候碰到两个"<“或者”>"放在一起的时候,一定要记得在中间加一个空格。这样编译器才不会把两个连在一起的符号判断成位运算的左移/右移。

priority_queue容器的使用方法
priorityqueue容器的使用方法大致如下表所示:

用法作用
q.top()返回priority_queue的首元素
q.push()向priority_queue中加入一个元素
q.size()返回priority_queue当前的长度(大小)
q.pop()从priority_queue末尾删除一个元素
q.empty()返回priority_queue是否为空,1为空、0不为空

注意:priority_queue取出队首元素是使用top,而不是front,这点一定要注意!!

C++ STL deque 容器

deque容器的概念
deque的意义是:双端队列。队列是我们常用而且必须需要掌握的数据结构。C++STL中的确有模拟队列的模板:#include中的queue和priority_queue。队列的性质是先进先出,即从队尾入队,从队首出队。而deque的特点则是双端进出,即处于双端队列中的元素既可以从队首进/出队,也可以从队尾进/出队。

即:deque是一个支持在两端高效插入、删除元素的线性容器。

deque模板存储在C++STL的#include<deque>中。

deque容器的使用方法
因为deque容器真的和queue容器大体相同,其使用方式也大体一致。下面把deque容器的使用方式以列表的方式放在下面:

用法作用
q.begin(),q.end()返回deque的首、尾迭代器
q.front(),q.back()返回deque的首、尾元素
q.push_back()从队尾入队一个元素
q.push_front()从队头入队一个元素
q.pop_back()从队尾出队一个元素
q.pop_front()从队头出队一个元素
q.clear()清空队列

除了这些用法之外,deque比queue更优秀的一个性质是它支持随机访问,即可以像数组下标一样取出其中的一个元素。
即:q[i]。

C++ STL set 容器

set容器的概念和性质
set在英文中的意义是:集合。
高中数学必修一集合那章,关于集合的性质,给出了三个概念:无序性、互异性、确定性。

那么,set容器的功用就是维护一个集合,其中的元素满足互异性。
我们可以将其理解为一个数组。这个数组的元素是两两不同的。

这个两两不同是指,如果这个set容器中已经包含了一个元素i,那么无论我们后续再往里假如多少个i,这个set中还是只有一个元素i,而不会出现一堆i的情况。这就为我们提供了很多方便。

但是,需要额外说明的是,刚刚说集合是有无序性的,但是set中的元素是默认排好序(按升序排列)的。(稍微说一句,set容器自动有序和快速添加、删除的性质是由其内部实现:红黑树(平衡树的一种)。这个东西过于高深我不会,所以不予过多介绍,有兴趣的小伙伴可以自行浏览相关内容。)

set容器的声明
set容器的声明和大部分C++STL容器一样,都是:容器名<变量类型> 名称的结构。前提需要开#include<set>库。如:

#include<set>
set<int> s;
set<char> s;
set<pair<int,int> > s;
set<node> s;
struct node{...};

set容器的使用
其实,C++STL容器的使用方式都是差不多的。我们完全可以举一反三地去类比。与bitset重定义了许多奇形怪状新的函数之外,其他都是大致相同的。所以笔者在此不再做幼稚的介绍,大家都是竞赛狗,应该都能自己看明白。

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(),这个性质可以用来判断集合中有没有这个元素。

其他好用的函数
下面介绍一些不是很常用,但是很好用的set容器的内置函数

s.lower_bound(),s.upper_bound();

熟悉algorithm库和二分、离散化的小伙伴会对这两个函数比较熟悉。其实这两个函数比较常用。但是对于set集合来讲就不是很常用。其中lower_bound返回集合中第一个大于等于关键字的元素。upper_bound返回集合中第一个严格大于关键字的元素。

s.equal_range();

这个东西返回一个pair(内置二元组),分别表示第一个大于等于关键字的元素,第一个严格大于关键字的元素,也就是把前面的两个函数和在一起。如果有一个元素找不到的话,就会返回s.end()。

C++ STL multiset 容器

multiset容器的概念和性质
set在英文中的意义是:集合。而multi−前缀则表示:多重的。所以multiset容器就叫做:有序多重集合。

multiset的很多性质和使用方式和set容器差不了多少。而multiset容器在概念上与set容器不同的地方就是:set的元素互不相同,而multiset的元素可以允许相同。

与set容器不太一样的地方:
s.erase(k);
erase(k)函数在set容器中表示删除集合中元素k。但在multiset容器中表示删除所有等于k的元素。

时间复杂度变成了O(tot+logn),其中tot表示要删除的元素的个数。

那么,会存在一种情况,我只想删除这些元素中的一个元素,怎么办呢?

可以妙用一下:

if((it=s.find(a))!=s.end())
    s.erase(it);

if中的条件语句表示定义了一个指向一个a元素迭代器,如果这个迭代器不等于s.end(),就说明这个元素的确存在,就可以直接删除这个迭代器指向的元素了。

s.count(k);
count(k)函数返回集合中元素k的个数。set容器中并不存在这种操作。这是multiset独有的。

C++ STL bitset 容器详解

bitset容器概论
bitset容器其实就是个01串。可以被看作是一个bool数组。它比bool数组更优秀的优点是:节约空间,节约时间,支持基本的位运算。在bitset容器中,8位占一个字节,相比于bool数组4位一个字节的空间利用率要高很多。同时,n位的bitset在执行一次位运算的复杂度可以被看作是n/32,这都是bool数组所没有的优秀性质。

bitset容器包含在C++自带的bitset库中。

#include
bitset容器的声明
因为bitset容器就是装01串的,所以不用在< >中装数据类型,这和一般的STL容器不太一样。< >中装01串的位数。

如:(声明一个105位的bitset)

bitset<100000> s;

对bitset容器的一些操作
1、常用的操作函数
和其他的STL容器一样,对bitset的很多操作也是由自带函数来实现的。下面,我们来介绍一下bitset的一些常用函数及其使用方法。

count()函数
count,数数的意思。它的作用是数出1的个数。即s.count()返回s中有多少个1.

s.count();
any()/none()函数
any,任何的意思。none,啥也没有的意思。这两个函数是在检查bitset容器中全0的情况。

如果,bitset中全都为0,那么s.any()返回false,s.none()返回true。

反之,假如bitset中至少有一个1,即哪怕有一个1,那么s.any()返回true,s.none()返回false.

s.any();
s.none();
set()函数
set()函数的作用是把bitset全部置为1.

特别地,set()函数里面可以传参数。set(u,v)的意思是把bitset中的第u位变成v,v∈0/1。

s.set();
s.set(u,v);
reset()函数

与set()函数相对地,reset()函数将bitset的所有位置为0。而reset()函数只传一个参数,表示把这一位改成0。

s.reset();
s.reset(k);

flip()函数
flip()函数与前两个函数不同,它的作用是将整个bitset容器按位取反。同上,其传进的参数表示把其中一位取反。

s.flip();
s.flip(k);

2、位运算操作在bitset中的实现
bitset的作用就是帮助我们方便地实现位运算的相关操作。它当然支持位运算的一些操作内容。我们在编写程序的时候对数进行的二进制运算均可以用在bitset函数上。

比如:

~:按位取反

&:按位与

|:按位或

^:按位异或

<< >>:左/右移

==/!=:比较两个bitset是否相等。

另外,bitset容器还支持直接取值和直接赋值的操作:具体操作方式如下:

s[3]=1;
s[5]=0;
这里要注意:在bitset容器中,最低位为0。这与我们的数组实现仍然有区别。

bitset容器的实际应用
bitset可以高效率地对01串,01矩阵等等只含0/1的题目进行处理。其中支持的许多操作对我们处理数据非常有帮助。如果碰到一道0/1题,使用bitset或许是不错的选择。

C++ STL map 容器

map容器的概念
map的英语释义是“地图”,但map容器可和地图没什么关系。map是“映射容器”,其存储的两个变量构成了一个键值到元素的映射关系。

比如下图:
在这里插入图片描述

我们可以根据键值快速地找到这个映射出的数据。

map容器的内部实现是一棵红黑树(平衡树的一种),因为比较复杂而且与理解并无多大关系,所以不予介绍,有兴趣的读者可以自己查阅相关的资料。

map容器的声明
map容器存在于STL模板库#include<map>中。使用的时候需要先开这个库。

比如:

#include<map>
map<int,char> mp;

这就建立了一个从一个整型变量到一个字符型变量的映射。

map容器的用法
因为map容器和set容器都是使用红黑树作为内部结构实现的。所以其用法比较相似。但由于二者用途大有不同,所以其用途还有微妙的差别。

其实,C++STL容器的使用方式都是差不多的。我们完全可以举一反三地去类比。与bitset重定义了许多奇形怪状新的函数之外,其他都是大致相同的。

常规操作
如其他C++STL容器一样,map支持基本相同的基本操作:

比如清空操作,函数clear(),返回容器大小size(),返回首尾迭代器begin(),end()等。

插入操作
map容器的插入操作大约有两种方法,第一种是类似于数组类型,可以把键值作为数组下标对map进行直接赋值:

mp[1]=‘a’;
当然,也可以使用insert()函数进行插入:

mp.insert(map<int,char>::value_type(5,'d'));

删除操作
可以直接用erase()函数进行删除,如:

mp.erase('b');

遍历操作
和其他容器差不多,map也是使用迭代器实现遍历的。如果我们要在遍历的时候查询键值(即前面的那个),可以用it->first来查询,那么,当然也可以用it->second查询对应值(后面那个)

查找操作
查找操作类比set的查找操作。但是map中查找的都是键值。

比如:

mp.find(1);

即查找键值为1的元素.

转载于:https://www.cnblogs.com/fusiwei/p/11823234.html

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值