STL 常用容器
一. 容器基本概述
STL是C/C++开发中一个非常重要的模板,而其中定义的各种容器也是非常方便使用。STL中的常用容器包括:顺序性容器(vector、deque、list)、关联容器(map、set)、容器适配器(queue、stack)
二. vector
使用它时需要包含头文件:
#include<vector>
vector 的优点:
- 指定一块如同数组一样的连续存储,但空间可以
动态扩展
。即它可以像数组一样操作,并且可以进行动态操作 - 随机访问方便,它像数组一样被访问,即重载了
[ ]
操作符和vector.at() - 节省空间,因为它是连续存储,在存储数据的区域都是没有被浪费的,但是要明确一点vector 大多情况下并不是满存的,在未存储的区域实际是浪费的
vector的缺点:
- 在内部插入、删除操作效率非常低,这样的操作基本上是被禁止的。Vector 被设计成只能在后端进行追加和删除操作,其原因是vector 内部的实现是按照顺序表的原理。
- 只能在vector 的最后进行push 和pop ,不能在vector 的头进行push 和pop
- 当动态添加的数据超过vector 默认分配的大小时要进行内存的重新分配、拷贝与释放,这个操作非常消耗性能。 所以要vector 达到最优的性能,最好在创建vector 时就指定其空间大小
1. vector 初始化
vector<int> a(10); //初始化 vector 容量 为10,每个元素默认填充为0
vector<int> b(10, 1); //每个元素默认填充为1
vector<int> c(a); // c的拷贝构造,把a的属性赋值给c
vector<int> d(a.begin(), a.begin() + 3); //定义了d的默认值为a中第0个到第2个(共3个)元素,并且 容量也是3
int e[7] = { 1,2,3,4,5,9,8 };
vector<int> f(e, e + 6); //初始数据为 从数组中0到5(共6个)个元素,容量也是6
2. 常用函数
vector<int> a;
vector<int> ::iterator iter = a.begin(); //获取迭代器首地址
vector<int> ::const_iterator const_iter = a.begin(); //获取const类型迭代器 只读
vector<int> ::const_iterator end_iter = a.end(); // 获取最后一个元素迭代器的下一个地址一
a.push_back(100); //尾插
a.pop_back(); //尾删
int size = a.size(); //个数
int capacity = a.capacity(); //容量
bool isEmpty = a.empty(); //判断是否为空
cout << a[0] << endl; //取得第一个元素
a.insert(a.end(), 5, 3); //从a.end位置插入5个值为3的元素
a.erase(a.begin(), a.begin() + 2); //删除a[0]-a[2]之间的元素,不包括a[2],其他元素前移
a.clear(); //清空
3. 遍历
vector<int> a(10);
// for循环
for (int i = 0; i < a.size(); i++)
{
cout << a[i] << endl;
}
//迭代器法
for (vector<int> ::iterator iter = a.begin(); iter != a.end(); iter++)
{
cout << *iter << endl;
}
三. deque
队列容器允许从一端新增元素,从另一端移除元素
队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为
队列中进数据称为 — 入队 push
队列中出数据称为 — 出队 pop
deque和vector类似,支持快速随机访问。二者最大的区别在于,vector只能在末端插入数据,而deque支持双端插入数据。deque的内存空间分布是小片的连续,小片间用链表相连,实际上内部有一个map的指针。deque空间的重新分配要比vector快,重新分配空间后,原有的元素是不需要拷贝的
deque<int> d;
//d.assign(10, 2); //将10个值为2的元素赋到deque中
// d.assign(d1.begin(), d1.end()); //接受序列容器的范围
//d.push_back(999); // 尾添
//d.push_front(666); // 首添
for (int i = 0; i < 100; i++)
{
d.push_back(i);
}
d.insert(d.begin() + 3, 99); //99 插入到 v 的第四个元素,后面的元素后移
d.insert(d.end() - 3, 9999); // 99插入到 v的倒数第四个元素
for (deque<int>::iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << endl;
}
d.pop_front(); // 首删
d.pop_back(); // 尾删
d.erase(d.begin() + 3); // 删除v 的第四个元素
d.erase(d.begin(), d.begin() + 3); // 删除前三个
d.front(); // 返回首个
d.back(); // 返回最后一个
d.clear();
cout << d.size() << endl; //0
四. map/ multimap
简介:
- map中所有元素都是pair
- pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
- 所有元素都会根据元素的键值自动排序
优点:
- 可以根据key值快速找到value值
map和multimap区别:
- map不允许容器中有重复key值元素
- multimap允许容器中有重复key值元素
map/multimap属于关联式容器,底层结构是用二叉树实现
map<int, string> map1;
// 常用操作方法
map1[3] = "Saniya"; //向下标为3的区域添加元素
map1.insert(pair<int, string>(1, "Siqinsini")); //pair方式插入元素
map1.insert(map<int, string> ::value_type(2, "Diyabi")); //value_type方式入元素
map1.insert(make_pair<int, string>(4, "V5")); //make_pair插入元素
string value = map1[3]; //数值方式获取元素,根据key取得value,key不能修改
map<int, string> ::iterator iter = map1.begin();//取得迭代器首地址
int key = iter->first; //第一个属性 key
string value = iter->second; //第二个属性 得value
map1.erase(iter); //通过迭代器删除
map1.erase(3); //根据key删除value
map1.size(); //元素个数
map1.empty(); //判断空
map1.clear(); //清空所有元素
//遍历
for (map<int, string> ::iterator iter = map1.begin(); iter != map1.end(); iter++)
{
int k = iter->first;
string v = iter->second;
cout << k << " " << v << endl;
}
五. set/ multiset
所有元素都会在插入时自动被排序
set/multiset属于关联式容器,底层结构是用二叉树实现
set和multiset区别:
- set不允许容器中有重复的元素
- multiset允许容器中有重复的元素
set<int> s;
s.insert(10);
s.insert(30);
s.insert(20);
s.insert(40);
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << endl;
}
s.size(); //返回容器中元素的数目
s.empty(); //判断容器是否为空
s.clear(); //清除所有元素
s.erase(++s.begin()); //删除pos迭代器所指的元素,返回下一个元素的迭代器
s.erase(20); // //删除容器中值为20的元素
s.erase(s.begin(), s.end()); // 删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
s.find(30); //查找30是否存在,若存在,返回该元素的迭代器;若不存在,返回set.end()
s.count(40); //统计40 出现的个数
六. list
功能: 将数据进行链式存储
链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
链表的组成:链表由一系列结点组成
结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域
STL中的链表是一个双向循环链表
list<int> l;
l.push_back(10);
l.push_back(20);
l.push_back(30);
l.push_back(40);
list<int> l2 (l.begin(), l.end()); // 根据区间赋值
l.push_back(60); // 尾添
l.push_front(70); // 首添
l.pop_back(); // 尾删
l.pop_front(); // 首删
l.insert(l.begin(), 11);//在迭代器位置插入10,返回新数据的位置
l.insert(l.begin(),2, 11);//在迭代器位置插入两个10,无返回值
l2.swap(l); // 交换
l.size(); // 大小
l.empty(); // 是否为空
l.resize(10); // 重新指定大小
l.clear(); // 移除容器的所有数据
l.remove(10); //删除容器中所有与10匹配的元素