前言
要我说c++和c在算法竞赛上有什么最明显的区别,我第一个想到的就是stl了,当你还在手写链表队列的时候,c++一个stl直接就可以写出来阿,我第一次看到大佬们用stl想不嫉妒都难,所以今天来系统的写一下stl,首先,我先来总结一下stl中的容器。因为本人时间较为琐碎,一下写完所有的容器不太现实,所以分开来写。
ps:因为本人的水平也十分有限,所以本系列文章以stl的入门为主,如果有纰漏欢迎大家指出~
vector
众所周知,c语言中数组是要有固定长度的,在我们开一个数组的时候,他的长度也就被固定下来了,而在stl中存在一个“动态数组”,你往vector中存多少数据,他的大小就是多少。
对于vector的实现方式,大概就是对于容器里的元素数量进行判断,当容器的存储数量达到容量时,进行一个倍增扩容。
下面来看关于vector的使用方法
#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关键字来定义一个迭代器,如下:
#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,但预留的位置并不初始化,同时也不可访问。(假设push_back后,vector的元素个数等于其容量,系统会自动对其进行一次倍增扩容)。
vec.max_size() vector所能容纳的最大元素数目,是由系统或者库来限制的,实际上,容器不一定能达到该大小。
对于一个新定义的vector,我们可以先预估一个合理的容量,通过reserve()进行预留,这样可以减少vector在动态扩展容量时的扩展次数,提高。
vec.insert() 插入一个元素。不同使用方法如下:
#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;
}
#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;
}
#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)不会发生改变。
例如:
#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 容器指定位置之前插入一个新的元素。他与push_back和insert相比效率更高,其利用传入的参数在容器管理的内存中直接构造元素;
vec.emplace_front() : 在容器的头部创建元素;
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~