STL容器
(7种)
vector(数组)
deque(双端数组)
stack(栈)
queue(队列)
list(双向链表)
set/multiset/unordered_set(集合)
map/multimap/unordered_map(键值对)
1. 理论基础
- 特点:数据结构和算法分离
- 组成:STL主要由容器、算法和迭代器三大部分组成
- 概念:容器:把你的元素copy到容器中;迭代器:相当于一个指针;算法:算法和迭代器无缝连接
- 分类:序列式容器(与插值顺序有关,如vector,list,deque),关联式容器(与插值顺序无关,如set)
2. 容器
下标用pos,迭代器用it
迭代器的区间范围,都是左闭右开
string
- 头文件:include< string >
常用函数 | 作用 |
---|---|
compare(str1,str2) | 比较两个字符串,也可以用>,<,==比较 |
erase(pos) | 删除pos到结尾 |
erase(pos,n) | 删除pos后面n个字符 |
find(str) | 查找str是否在调用的字符串中出现过,返回pos |
rfind(str) | 反向查找第一个字符的索引 |
insert(pos,str) | 在第pos位置前插入str(必须是字符串,不能是字符) |
stoi/stof(string) | 把字符串转成int/float型 |
substr(pos,n) | 返回pos后面n个字符 |
substr(pos) | 返回pos到结尾的串 |
to_string(val) | 把数值val转成string |
append | 函数常用的三个功能:直接添加另一个完整的字符串:如str1.append(str2);添加另一个字符串的某一段子串:如str1.append(str2, 11, 7);添加几个相同的字符:如str1.append(5, ‘.’);注意,个数在前字符在后.上面的代码意思为在str1后面添加5个"." |
c_str() | 把c++中string变成c中的字符数组 |
vector
- 动态数组(可以不用固定大小),连续储存结构
- 头文件: include< vector >
- 使用方法:
常用函数 | 作用 |
---|---|
assign | 将区间[first,last)的元素赋值到当前的vector容器中,或者赋n个值为x的元素到vector容器中,这个容器会清除掉vector容器中以前的内容,即size属性的值会改变 |
back() | 返回尾部元素 |
clear() | 清空所有元素 |
erase(it1,it2) | 删除区间元素 |
find(it1,it2,val) | 找到范围内的val值 |
front() | 返回头部元素 |
insert(it,val) | 插入元素 |
pop_back() | 弹出尾部元素,无返回值 |
push_back() | 添加尾部元素,无返回值 |
reserve() | 增加vector中的capacity,但它的size没有改变,它改变容器的预留空间,但在空间内不真正创建元素对象 |
resize() | 改变了vector的capacity同时也改变了它的size |
-
一维数组初始化:
vector a(size, val); -
二维数组初始化:
vector<vector> a(rows,vector(cols,val)); -
直接赋值
vector<int> a={1,2,3};
-
vector作为函数参数时,是深拷贝,加上&才是浅拷贝
-
vector_a = vector_b /深拷贝
-
清除内存:错误:vector.clear() 正确:v.clear(); vecotr().swap)(v) ; 或 v.clear() ; v.shrink_to_fit();
deque
- 双端队列
- 头文件:inlcue< deque >
- 使用方法:
常用函数 | 作用 |
---|---|
back() | 返回尾部元素 |
front() | 返回头部元素 |
insert(it,val) | 插入元素 |
pop_back() | 弹出尾部元素,无返回值 |
pop_front() | 弹出头部元素,无返回值 |
push_back() | 添加尾部元素,无返回值 |
push_front() | 添加头部元素,无返回值 |
stack
- 栈模型,先入后出
- 头文件: include< stack >
- 使用方法:
常用函数 | 作用 |
---|---|
push() | 入栈 |
pop() | 出栈 |
top() | 栈顶元素 |
empty( ) | 元素是否为空 |
queue
- 队列模型,先进先出
- 头文件:include< queue >
- 使用方法:
常用函数|作用
-|
push()|入队
pop()|出队
front()|队头元素
back()|队尾元素
priority_queue
- 优先级队列,本质是由堆实现的
- 头文件: include< queue >
- 使用方法:
常用函数|作用
-|
top()|访问队头元素(与stack不同)
pop()|出队
push()|入队
-
可自定义排序规则:priority_queue< Type,Containew,Functional >
-
当需要用自定义数据或自定义规则时,需要传入这三个参数。
priority_queue<int> p;//默认最小值优先队列 priority_queue<int, vector<int>, less<int>> p;//最小值优先队列 priority_queue<int, vector<int>, greater<int>> p;//最大值优先队列
注:
- 用到greater,头文件要加:include< functional >
- 优先的意思是放在队列末尾,这样可以最后出去
list
- 双向链表
- 可以高效地进行插入和删除元素,非连续存储结构
- 不可以随机存取元素,不支持下标操作
- list和vector的区别:vector内存空间是连续的,故而随机访问元素容易,但插入和删除元素困难(操作后其他元素都要变);list内存空间是不连续的,故而随机访问元素困难,而插入和删除元素简单
- 在n号位插入元素,则n号位为插入元素,之前的n号位及之后元素整体后移一位。
- 头文件:include< list >
常用函数|作用
-|
erase(it)|删除元素
erase(it1,it2)|删除区间元素,左闭右开
insert(it,val)|插入元素
pop_back()|弹出尾部元素,无返回值
pop_front()|弹出头部元素,无返回值
push_back()|添加尾部元素,无返回值
push_front()|添加头部元素,无返回值
set/multiset/unordered_set
- 集合容器
- set所包含的元素是唯一的,集合的元素是按照一定的顺序自动排列的,不能指定插入位置,时间复杂度O(logN)
- multiset与set的区别是multiset中同一值可以出现多次
- unordered_set存储的元素是无序的,和输入顺序无关,时间复杂度O(1)
- set经过排序,通过红黑树实现;unordered_map不经过排序,通过hash表实现
- 头文件:include< set > include< unordered_map >
- 改变排序顺序:
set< int,less< int > > (从小到大,默认)
set< int,greater< int > >(从大到小)引入include
set<type,cmp>(自定义比较函数) 自定义一个结构体,重载()运算符
struct cmp{
bool operator()(type a, type b){
return …
}
};
常用函数|作用
-|
count(val)|返回值1为找到元素,0为未找到
find(val)|查找val元素,返回迭代器
insert(val)|插入元素
lower_bound(val)|返回大于等于val的迭代器
upper_bound(val)|返回大于val的迭代器
map/multimap/unordered_map
- 关联式容器
- 一个map是一个键值对序列,即(key,value)对,它提供了基于key的快速检索能力,时间复杂度O(logN)
- map中key是唯一的,元素按一定顺序排列,不能指定插入位置
- 插入< key,value >键值对时,map就会自动按照key的大小顺序进行存储,**因而作为key的类型必须能够进行大小运算的比较。**比如int、double、string、char等类型。
- multimap中相同的key可以出现多次,故而一个重要的应用是分组
- unordered_map存储的元素是无序的,与输入顺序无关,时间复杂度O(1)(虽然无序,但也不能改变其顺序)
- 头文件:include < map > include< unordered_map >
- map< type1,type2 >
- 迭代器返回变量:it->first ,it->second;(分别返回key和value)
- 常见3种插入方法
map[1]="teacher01’;
map.insert(make_pair(1,“teacher01”));
pair<int,string> a={1,“string”}; map.insert(a);
注意map.insert函数返回的是一个pair,若果key存在,则报错;数组方法若果key存在,则覆盖
常用函数|作用
-|
find(key)|返回key的迭代器,若不存在,返回map.end()
erase(key)|删除元素
容器共性机制
- 所有容器提供的都是值语意,而非引用语意。容器执行插入元素的操作时,内部实施拷贝动作。所以STL存储的元素必须能够被拷贝。
- 除了stack和queue,每个容器都提供返回迭代器的函数,用来访问元素
- 各个容器的使用场合
deque适用于排队购票系统
list支持频繁的不确定位置元素的移除和插入
set适用于记录的存储
map存储用户信息
3. 迭代器
3.1 erase导致迭代器失效
-
对于关联容器(如map, set, multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可
for(iter = cont.begin(); it != cont.end();) { (*iter)->doSomething(); if(shouldDelete(*iter)) cont.erase(iter++); elseC ++iter; }
-
对于序列式容器(如vector,deque),删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。还好erase方法可以返回下一个有效的iterator。
for(iter = cont.begin(); iter != cont.end();) { (*it)->doSomething(); if(shouldDelete(*iter)) iter = cont.erase(iter); else ++iter; }
-
对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种方法都可以使用
4. 算法
- 算法部分是由头文件,,组成
- < algorithm >是STL头文件中最大的一个,包括交换、查找、遍历、复制、修改、反转、排序等
- < numeric >很小,包括加法和乘法在序列上的一些操作
- < functional >定义了一些模板类,用以声明函数对象
函数对象(仿函数)
本质是类重载了一个operator(),运用了回调函数的理念
- 一元函数对象:函数参数是1个;
- 二元函数对象:函数参数是2个;
- 一元谓词:函数参数是1个,函数返回值是bool型,可以作为一个判别式,谓词可以是一个仿函数,也可以是一个回调函数
- 二元谓词:函数参数2个,函数返回值是bool型
预定义函数对象
- 大多数包含在< functional >
- 算术类:加减乘除求余取反
- 关系类:大于小于等于
- 函数适配器:将一种函数对象转化成另一种符合要求的函数对象,常见的有绑定器:将二元函数对象的一个实参绑定到一个特殊的值上,将其转成一元函数对象
常用函数适配器|作用
-|
bind1st(op,value)|将值绑定到二元函数对象的第一个实参
bind2nd(op,value)|将值绑定到二元函数的第二个实参
not1(op)|对一元函数对象结果取反
not2(op)|对二元函数对象结果取反
常用algorithm算法
函数 | 作用 |
---|---|
max(a,b) | 最大值 |
min(a,b) | 最小值 |
fill(it1,it2,val) | 给区间范围内元素赋相同初值 |
reverse(it1,it2) | 逆转范围内元素,左闭右开 |
reserve() | 重新指定容器的容量大小,如果小于原来的容量,则不起作用,如果大于,则重新分配一块更大的连续空间,将原来容器元素复制过来,并删除原来容器的存储空间。 |
resize(n) | 重新指定容器有效的元素个数;若原本容器的size小于n,则扩充元素,元素值设为默认值(如果希望多出的部分不是默认值,则调用resize(n,val)将不足的部分用val填充),若大于n,则只保留容器前n个元素 |
sort(it1,it2) | 排序,可以按写好的函数对象规则排序(默认从小到大) |
stable_sort(it1,it2) | 和sort的区别在于,该函数遇到两个数相等时,不对其交换顺序 |
swap(a,b) | 交换a,b |
find(it1,it2,val) | 找到val的的迭代器下标 |
remove_if(begin,end,op) | 参数是迭代器。op是lamda函数,如果函数返回为真,则将当前所指向的参数移到尾部。返回值是被移动区域的首个元素。此函数无法真正删除元素,只能把要删除的元素移到容器末尾并返回要被删除元素的迭代器,然后通过erase成员函数来真正删除。一般remove_if和erase函数是成对出现的。 |
pos = std::remove_if(pos, end, [prev](DMatch a) {return (a.queryIdx == (*prev).queryIdx;}
overlaps.erase(pos, overlaps.end());
- for_each():用指定函数依次对指定范围内所有元素进行迭代访问。
定义:for_each(begin,end,func); - transform():遍历所有元素,可对容器的元素进行修改
定义1:transform(b1,e1,b2,op)
定义2:transform(b1,e1,b2,b3.op) - count_if():查找满足条件的元素的个数
定义:count_if(begin,end,func); - merge():合并两个有序序列,存放到另一个序列
定义:merge(begin1,end1,begin2,end2, begin3) - random_shuffle():随即洗牌
定义:random_shuffle(begin,end); - copy():拷贝
定义:copy(begin1,end1,begin2); - replace():替换
定义:replace(begin,end,oldvalue,newvalue); - accumulate():对范围内元素求和,再加上一个由val定义的初始值,头文件需加“numeric”
定义:accumulate(begin,end,val); - set_union():构造一个有序序列,包含两个有序序列的并集
定义:set_union(begin1,end,begin2.end2,begin3); - set_intersection():构造一个有序序列,包含两个有序序列的交集
定义:set_intersection(begin1,end,begin2.end2,begin3)
注:
-
sort一般只对vector,deque容器的常规数据类型进行排序,其它情况需要自定义cmp函数
sort(begin,end,cmp); bool cmp(type a,type b){ return ... } sort(begin,end,greater<type>()); //有括号
-
stable_sort函数在数组里运用和sort一样,但当函数参数传入是结构体时,就会发现两者之间的明显区别
functional的常见用法
- bind(函数适配器)
auto newfunc=std::bind(func,n,std::placeholders::_1)
说明:表示绑定函数func的第一个参数为n,func的第二个参数由newfunc的第一个参数指定。