STL容器

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());
  1. for_each():用指定函数依次对指定范围内所有元素进行迭代访问。
    定义:for_each(begin,end,func);
  2. transform():遍历所有元素,可对容器的元素进行修改
    定义1:transform(b1,e1,b2,op)
    定义2:transform(b1,e1,b2,b3.op)
  3. count_if():查找满足条件的元素的个数
    定义:count_if(begin,end,func);
  4. merge():合并两个有序序列,存放到另一个序列
    定义:merge(begin1,end1,begin2,end2, begin3)
  5. random_shuffle():随即洗牌
    定义:random_shuffle(begin,end);
  6. copy():拷贝
    定义:copy(begin1,end1,begin2);
  7. replace():替换
    定义:replace(begin,end,oldvalue,newvalue);
  8. accumulate():对范围内元素求和,再加上一个由val定义的初始值,头文件需加“numeric”
    定义:accumulate(begin,end,val);
  9. set_union():构造一个有序序列,包含两个有序序列的并集
    定义:set_union(begin1,end,begin2.end2,begin3);
  10. set_intersection():构造一个有序序列,包含两个有序序列的交集
    定义:set_intersection(begin1,end,begin2.end2,begin3)

注:

  1. sort一般只对vector,deque容器的常规数据类型进行排序,其它情况需要自定义cmp函数

     sort(begin,end,cmp);
     bool cmp(type a,type b){
      	return ...
     }
     sort(begin,end,greater<type>());  //有括号
    
  2. stable_sort函数在数组里运用和sort一样,但当函数参数传入是结构体时,就会发现两者之间的明显区别

functional的常见用法

  1. bind(函数适配器)
    auto newfunc=std::bind(func,n,std::placeholders::_1)
    说明:表示绑定函数func的第一个参数为n,func的第二个参数由newfunc的第一个参数指定。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值