前言

要我说c++和c在算法竞赛上有什么最明显的区别,我第一个想到的就是stl了,当你还在手写链表队列的时候,c++一个stl直接就可以写出来阿,我第一次看到大佬们用stl想不嫉妒都难,所以今天来系统的写一下stl,首先,我先来总结一下stl中的容器。因为本人时间较为琐碎,一下写完所有的容器不太现实,所以分开来写。

ps:因为本人的水平也十分有限,所以本系列文章以stl的入门为主,如果有纰漏欢迎大家指出~

vector

众所周知,c语言中数组是要有固定长度的,在我们开一个数组的时候,他的长度也就被固定下来了,而在stl中存在一个“动态数组”,你往vector中存多少数据,他的大小就是多少。

vector 的 size() 是当前元素个数,capacity() 是不重新分配内存时能容纳的元素个数。当一次插入会使元素个数超过容量时,需要重新分配存储空间。具体扩容倍数由实现决定,C++ 标准并没有规定必须翻倍;尾部插入的复杂度保证是摊还常数时间。

下面来看关于vector的使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream> 
#include<vector>//使用前
using namespace std;
int main()
{
vector<int> vec;//声明一个vector

for(int i=0;i<20;i++)
{
int n;
cin>>n;
vec.push_back(n);//在vec后面插入这个数字
}
vector<int>::iterator it;//定义it为迭代器。
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<"\n";//输出vector中的元素
return 0;
}

代码中vector<int>::iterator it;定义的it为迭代器,可以理解为stl容器中的指针,当然这个形容不是很贴切,只是为了便于理解,具体关于迭代器和指针的一些区别我就先不总结了。

当然遍历vector容器也可以用下标访问。

在c++11中,我们可以用auto关键字来定义一个迭代器,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream> 
#include<vector>//使用前
using namespace std;
int main()
{
vector<int> vec;//声明一个vector

for(int i=0;i<20;i++)
{
int n;
cin>>n;
vec.push_back(n);//在vec后面插入这个数字
}
for(auto it=vec.begin();it!=vec.end();it++)//当然在c11中可用auto
cout<<*it<<"\n";//输出vector中的元素
return 0;
}

关于vector,还有很多其他使用方法

vec.begin()  返回vector中的首迭代器(指向第一个元素)。

vec.end()    返回vector中的尾迭代器(指向最后一个元素的下一个节点)。

vec.push_back()    在vector的末尾加入一个元素。

vec.pop_back()    在vector的末尾删去一个元素。

vec.empty()   验证vector是否为空,若为空返回1,不为空返回0。

vec.size()   返回vector长度(元素个数)。

vec.capacity()   返回vector的容量(不一定与vec.size()相等)。

vec.swap(b)      将vec和b中的元素进行交换。

vec.clear()    清空vector。

vec.resize(a,b)    指定容器的长度为a,若容器变长,则以b(若无b,则填入0)填充新位置,如果容器变短,则末尾超过容器长度的元素被删除。

vec.reserve(a)    当 a 大于当前容量时,将容量增加到至少 a;否则容量不变。它不会改变 size(),预留的存储空间还不是已构造的元素,不能通过下标访问。后续插入只有在新大小将超过当前容量时,才需要重新分配内存。

vec.max_size()     vector所能容纳的最大元素数目,是由系统或者库来限制的,实际上,容器不一定能达到该大小。

对于一个新定义的vector,我们可以先预估一个合理的容量,通过reserve()进行预留,这样可以减少vector在动态扩展容量时的扩展次数,提高。

vec.insert()  插入一个元素。不同使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int a[4]={0,1,2,3};
vector<int> vec(a,a+4);//将数组的值赋给vec
vector<int>::iterator it;
vec.insert(vec.begin()+1,3);//在第一个元素(从0算起)的位置插入3
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<' '; //输出 0 3 1 2 3
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int a[4]={0,1,2,3};
vector<int> vec(a,a+4);//将数组的值赋给vec
vector<int>::iterator it;
vec.insert(vec.begin()+1,3,5);//在第一个元素(从0算起)的位置插入3个5
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<' '; //输出 0 5 5 5 1 2 3
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int a[4]={0,1,2,3};
int b[4]={6,7,8,9};
vector<int> vec(a,a+4);//将数组的值赋给vec
vector<int>::iterator it;
vec.insert(vec.begin()+1,b+1,b+3);//在第一个元素(从0算起)的位置插入数组b的b+1~b+2,(不包括b+3);
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<' '; //输出 0 7 8 1 2 3
return 0;
}

erase(it)   删除 vector 容器中 it 迭代器指定位置处的元素,并且返回指向被删除元素下一个位置元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会发生改变。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int a[4]={0,1,2,3};
vector<int> vec(a,a+4);//将数组的值赋给vec
auto it=vec.begin();
vec.erase(it);//删除第一个元素
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<" ";
cout<<endl;//输出1,2,3(第一个元素0被删除)
cout<<vec.size()<<endl;//结果为3,因为共有三个元素。
cout<<vec.capacity();//结果为4
return 0;
}

注意:insert和erase都有可能导致迭代器失效

迭代器失效大概有两种情况,我简单介绍一下,

1.迭代器所指向的元素意义改变

2.迭代器“越界操作”,指向了未知的区域。

篇幅原因,我准备在之后的文章中再详细介绍迭代器,这里大家可以先简单了解以下。

vec.emplace()     C++ 11 标准新增加的成员函数,用于在 vector 容器指定位置之前构造并插入一个新元素。它将参数转发给元素的构造函数,可能省去临时对象的构造或移动,但不保证总比 insert 或 push_back 更快;在中间插入仍可能移动后续元素,扩容时仍可能重新分配内存。

vector 没有 emplace_front() 成员函数。在头部构造元素可使用 vec.emplace(vec.begin(), 参数...),但这不是常数时间的头部插入。

vec.emplace_back() : 在容器的尾部创建元素。

emplace在其他一些stl容器也有所应用

能在vector使用的其他常用算法(algorithm)

1.sort

sort(vec.begin(),vec.end())       对vec整体从小到大排列

注意:排序的范围包括括号内第一项,而不包括括号内第二项

2.find

find(vec.begin(),vec.end(),1)         在vec整体范围中,查找元素1,并返回他所在位置。

find函数同上,范围不包括括号内第二项

3.reverse

reverse(vec.begin(),vec.end())        在vec整体范围中,倒置元素。如1,3,2  reserve 后变为2,3,1。

同上qwq,范围不包括括号内第二项

完~

一些无聊的后话

       这篇虽然篇幅不长但是我还是来回整理了好几天,主要是这几天真的忙死了,没什么时间来写,每次忙完别的事再回来写都忘了上次写到哪里了hhhh,所以断断续续在今天总算写完了,如果喜欢的话就给个点赞或者评论关注一下吧(虽然我很菜写不出什么高端东西来,这段时间还是比较忙,如果有时间的话还会来继续把stl容器写完的,毕竟stl这么有意思的东西,不好好整理学习一下怎么行呢。好了,感谢您的阅读,祝您生活愉快~

qwq~

校订记录(2026-10-09):本页从原文迁入后,校正了扩容、reserve 与 emplace 的说明;原始示例代码和原文日期保留。参考:C++ 标准工作草案的 vector 接口、容量规则与插入操作。