C++ STL总结

2023-05-16

C++ STL分为5部分
容器,迭代器,空间适配器,函数对象,泛型算法,适配器
一、容器
理解容器的作用:
容器的主要作用是用于存储对象(这里说的对象时指的是包含基本数据类型的数据和复合数据类型实例的对象),提供一种工具来减少我们平时一些数据结构,比如说链表,队列,栈的一些操作和基础数据结构的封装。
容器分为三类:
顺序容器:比如说vetor,list,deque
(1)向量容器:vector,底层数据结构是内存连续的数组,可以动态调整数组大小(以二倍增长,先申请新的内存,然后将原来的数据放到新的内存中,释放原来的内存,将数组头指针更新为新的内存区域),未初始化时大小为0,,随机访问效率高,头部增删,中间增删操作需要移动整个数组,开销比较大。查找效率高 使用时需要引入vector头文件 在堆上分配内存
push_back O(1)
insert(it, val) O(n)
erase() O(n)
pop_back O(1)
swap() 效率
(2)双向链表list底层维护一个双向链表,内存不连续,增删数据代价小,创建时默认开辟头结点
各list操作的时间复杂度 在堆上分配内存
push_back O(1)
insert(it, val) O(1)
erase() O(1)
pop_back O(1)
swap() 效率
push_front O(1)
pop_front O(1)
splice(链表的切片)
(3)双端队列deque,我们看如下定义,来分析它的底层,内存分段连续, 8-16-32 2倍增长一维, oldSize/2 8/2 = 4 16/2 = 8
是一个分段连续的二维数组,初始第一维为8,第二维为4
动态开辟的二维数组 8个 4
默认没开辟空间
支持[]访问,在头尾的增删操作效率高;还有较高的随机访问效率;它支持在两端的操作:push_back,push_front,pop_back,pop_front等,并且在两端操作和List操作效率差不多。
vector只是在序列的尾端插入数据时插入时效率才高,而deque的分段管理使得不管在尾部还是前端也提供常数时间的insert和erase操作,而且在体积增长方面,vector更加有效
对比:
vector在尾部的添加删除元素,访问速度(指的是随机访问)快
list可以快速的在所有地方进行增删元素,但是只提供最后和最前面元素的快速访问
deque在最开始和最后面添加元素一样快,并提供随机随机访问方法像vector一样随机访问,但是由于自身内存部分连续的原因,效率要低于vector的随机访问
使用场景
1,如果需要高效的随机存取,不在乎插入删除的效率,推荐使用vector
2,如果你需要大量的插入和删除,而不关心随机存取,则推荐使用list
3,如果需要随机存取,而且关心两端的插入和删除,则应该使用deque
关联容器:
所谓关联容器:就是存在类似于关系数据库中的Key value键值对,按照key 进行存储对应的value值
而关联容器又分为set(集合)和map两大部分.
set:
底层数据结构:红黑树 增删查时间复杂度:O(log2n)
应用特点:数据排序了,非常合适范围查找
分为muitiset和set,unordered_set
set由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用于元素对的谓词排列,没有两个不同的元素能够拥有相同的次序,并且是有序的
mutiset:允许存在两个次序相等的元素的集合 

unordered_set无序set
map分为三类 一帮的map和unorderded_map,multimap
map是有序的,底层是红黑树,它是真正意义上的key-value键值对,因此在初始化时需要指定key,value的类型,key-value之间使用hash映射函数进行key到value的映射,常见的映射函数有:
·直接取余法:f(x):= x mod maxM ; maxM一般是不太接近 2^t 的一个质数。
·乘法取整法:f(x):=trunc((x/maxX)*maxlongit) mod maxM,主要用于实数。
·平方取中法:f(x):=(x*x div 1000 ) mod 1000000); 平方后取中间的,每位包含信息比较多。
解决hash conflict的方法有:链地址法,再哈希法,线性探测法
hash因子:已存元素个数/hash table表项个
而对于关联容器而言,特别是map三兄弟,它们都是key-value类型,所以它们的迭代器在设计上就与顺序容器的不同,map兄弟的迭代器是pair类型的,有first和last两个成员,first表示key,last表示值
并且在给map插入的时候需要进行make_pair打包一下,具体如下
可以看出map是有序的,并且默认排序方式是从小到大
unorderded_map是无序的,底层是真正意义上的hash_table(hash_table需要查找效率,解决hash冲突的方法),在插入时还是需要make_pair打包
底层数据结构:哈希表(链地址法、拉链法) 增删查的时间复杂度:接近O(1)【为什么是接近,因为哈希冲突/哈希碰撞是不可能避免的】
应用特点:快速的增删查,但是哈希表的数据是无序的,非常不适合范围查找
建议:80-90%都是使用哈希表,只有应用场景中需要数据有序,范围查找的时候,才会用红黑树实现的有序关联容器
multimap也是类似的,只不过提供多重映射,允许键值重复的存储
二.容器适配器
先理解什么是适配器,适配器就是一个中间层,比如你的电视机是三座的,而你的插座是二座的,现在你需要一个中间层,即插在二座的一个带有三插插板的一个中间件。这个中间件就是适配器。
STL有三种容器适配器stack,queue,priority_queue分别包装了deque,deque,和vector,三种适配器都实现对应名字的功能,stack的先进后出,queue先进先出,priority_queue默认维护一个小根堆,当然也可以指定greater<>函数对象改变默认构造方式,是它变为一个大根堆。
当然,它们的底层我们也可以自己指定,但是由于priority_queue要求支持[]所以我们可以建立在vector或者deque上,不能建立在list上vector由于要求;stack要求数据先进后出,所以可以使用任何一种数据结构,因为它们都提供了pop_back,push_back方法;queue特点是先进先出,因此要求提供pop_front的操作,所以vector不能作为queue的底层数据结构
指定容器的底层数据结构:
stack提供了5中方法
1.empty()  堆栈为空则返回真 
2.pop()  移除栈顶元素 
3.push()  在栈顶增加元素 
4.size()  返回栈中元素数目 
5.top()  返回栈顶元素 
队列提供了6种
1.back()  返回一个引用,指向最后一个元素 
2.empty()  如果队列空则返回真 
3.front()  返回第一个元素 
4.pop()  删除第一个元素 
5.push()  在末尾加入一个元素 
6.size()  返回队列中元素的个数 
优先级队列提供了5种方法
1.empty()  如果优先队列为空,则返回真 
2.pop()  删除第一个元素 
3.push()  加入一个元素 
4.size()  返回优先队列中拥有的元素的个数 
5.top()  返回优先队列中有最高优先级的元素
prioirty_queue可以用于大数top k问题
三、迭代器
迭代器提供对于容器遍历,访问的包装接口。
一般我们遍历数组访问数组元素的时候,都写出类似下面的代码
for(int i=0;i<n;i++)
{
cout<<a[i]<<endl;
}
但是现在使用STL的容器,有些就不能使用上面的方法了,瓶颈在于map底层是红黑树,需要使用迭代器进行访问和遍历
for(vector<int>:: iterator it=vec.begin();it!=vec.end();++it)
{
cout<<*it<<endl;
}
或者是C++11的语法
for(vector<int> it:vec)
{
cout<<*it<<endl;
}
对于顺序容器来说,迭代器是对于指针的封装(因为顺序容器的访问本质在于按照指针进行遍历),
如下
关联容器map
迭代器分为三类:
正向迭代器 iterator begin()/end()
反向迭代器 reverse_iterator rbegin()/rend()
插入行迭代器 =》 泛型算法 copy(first, last, dest);
back_insert_iterator => back_inserter => push_back
front_insert_iterator => front_inserter => push_front
insert_iterator => inserter => insert(it, val);
istream_iterator => cin
迭代器部分主要由头文 件<utility>,<iterator>和<memory>组成。<utility>是一个很小的头文件,它包括了贯穿使用在STL中的几个模板的声明,<iterator>中提供了迭代器使用的许多方法,而对于 <memory>的描述则十分的困难,它以不同寻常的方式为容器中的 元素分配 存储空间,同时也为某些算法执行期间产生的临时对象提供机制,<memory>中的主要部分是 模板类 allocator,它负责产生所有容器中的默认分配器。
四、泛型算法
泛型其实是指C++的模板编程而言的,类型变成了参数,只能应用于STL容器中,因为大多数泛型算法都是针对于容器的迭代器而言的,如下
_FwdIt就是迭代器
泛型算法提供无差异的容器操作,使得代码复用提高,使用更加统一
算法部分主要由 头文件 <algorithm>,<numeric>和<functional>组成。<algorithm>是所有STL头文件中最大的一个(然而它很好理解),它是由一大堆模版函数组成的,可以认为每个函数在很大程度上都是独立的,其中常用到的功能范围涉及到 比较、交换、查找、遍历操作、复制、修改、移除、反转、排序、合并等等。<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。<functional>中则定义了一些 模板类,用以声明 函数对象。
sort(first, last)
sort(first, last, Compare); // greater/less
find(first, last, val);
find_if(first, last, Compare(val)); // greater/less + bind1st/bind2nd
copy(first, last, dest);
编写自定义的greater和Less泛型算法
template<typename T>
inline bool greaterFunc(T a, T b)
{
return a > b;
}
template<typename T>
inline bool lessFunc(T a, T b)
{
return a < b;
}
正向迭代器(从前往后遍历) iterator vec.begin() vec.end()
反向迭代器(保留,从后往前遍历) reverse_iterator vec.rbegin() vec.rend()
插入型迭代器 => 用在泛型算法当中的,可以通过迭代器给容器添加元素
前插型迭代器 =》 push_front
后插型迭代器 =》 push_back
按位置插入型迭代器 =》 insert
流迭代器 =》 用在泛型算法当中的
输入流迭代器 istream_iterator
输出流迭代器 ostream_iterator
五、函数对象
函数对象其实和普通对象没什么差别,只不过是在函数对象类中实现了对于()运算符的重载运算操作而已,比如下面的
template<typename T>
class MyBase
{
public:
typedef T value_type;
};
template<typename T>
class MyGreater : public MyBase<T>
{
public:
bool operator()(T a, T b)
{
return a > b;
}
};
template<typename T>
class MyLess : public MyBase<T>
{
public:
bool operator()(T a, T b)
{
return a < b;
}
};
另外:C++ STL 库比较元素大小相关的函数对象,只有二元的函数对象。但是泛型算法,有的只需要一元函数对象
二元函数对象 + () ======》 一元函数对象
C++ STL库里面 函数对象的另外一个应用
绑定器 都是绑定高元函数对象 高元的函数对象+绑定器 =》低元的函数对象
bind1st =》 把二元函数对象的operator()函数的第一个参数进行绑定
bind2nd =》 把二元函数对象的operator()函数的第二个参数进行绑定
取反器
not1 =》 给一元函数对象取反 ture -> false
not2 =》 给二元函数对象取反 false -> true
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ STL总结 的相关文章

随机推荐

  • traj_out variable ‘std:ofstream’ has initializer but incomplete type

    variable 39 std ofstream has initializer but incomplete type 或者是variable 39 std ifstream has initializer but incomplete
  • perl处理excelwenjian

    usr bin perl use strict use Win32 OLE qw in with use Win32 OLE Const 39 Microsoft Excel 39 Win32 OLE Warn 61 3 die on er
  • C++ox 之 lambda

    http www cnblogs com allenlooplee archive 2012 07 03 2574119 html 今天看了博文 xff0c 之前对于lambda的理解比较粗陋 xff0c 今天再学习一下 不得不说我是一个极
  • __x_a != __x_a什么时候不成立?

    define isnan x extension typeof x x a 61 x builtin expect x a 61 x a 0 在看redis源码的时候发现了一个有趣的东西 xff0c 这个宏对是否是有效的实数进行了判断 这个
  • pthread_mutex_trylock的问题及解决

    在需要使用非阻塞的锁时 xff0c trylock是一个比较好的选择 xff0c 但是使用的时候碰见了一些问题 xff1a 需要使用PTHREAD MUTEX ERRORCHECK NP 来定义一个检错锁 xff0c 但是不管如何都编译不过
  • thrift, Protocol Buffers and MsgPack 的序列化对比

    啥是序列化 xff1f 序列化是将对象状态转换为可保持或传输的格式的过程 与序列化相对的是反序列化 xff0c 它将流转换为对象 这两个过程结合起来 xff0c 可以轻松地存储和传输数据 为啥要序列化 xff1f 1 以某种存储形式使自定义
  • python处理xlsx

    一 读取excel 这里介绍一个不错的包xlrs 可以工作在任何平台 这也就意味着你可以在Linux下读取Excel文件 首先 xff0c 打开workbook xff1b import xlrd wb 61 xlrd open workb
  • php解析请求url并返回json数据

    lt php paserRequest SERVER 34 QUERY STRING 34 function paserRequest strReq parse str strReq 解析请求参数 cpIds 61 explode 39 3
  • 对TTL电平,232电平 CMOS电平做下总结

    xff08 一 xff09 TTL电平标准 输出 L xff1a lt 0 8V xff1b H xff1a gt 2 4V 输入 L xff1a lt 1 2V xff1b H xff1a gt 2 0V TTL器件输出低电平要小于0 8
  • twemproxy for redis使用说明及简单分析

    redis的数据量在内存高过50G时系统出现了明显的瓶颈 为了解决这个问题 xff0c 笔者找了些相关的资料 xff0c 发现了这个开源软件 功能很强大 xff0c 包含了last fm的ketama的一致性hash算法 xff0c 对于笔
  • static的map成员的初始化顺序居然和编译器相关

    我十分不敢相信这是真的 xff0c 但是确实发生了 xff0c 而且足足折腾了我5个小时 core文件的内容大概是这样 xff1a 0 0x0000003071664cba in std Rb tree decrement std Rb t
  • 创建在mac电脑本地搭建nginx,并模拟打包发布前端构建包

    1 本地安装nginx服务brew install nginx 报No such file or directory 64 rb sysopen Users wangjie Library Caches Homebrew downloads
  • 关于swiftUI和UIKit混用

    思路无非就是自定义一个结构体view实现UIViewRepresentable协议 xff0c 然后就可以作为一个swiftUI组件进行调用了 1 我们要定义一个CustomView这个名字随便起 struct CustomView UIV
  • swiftUI自定义Environment的Key

    1 创建一个结构体作为要共享的值 struct RefreshData var thresold CGFloat 61 0 var progress Double 61 0 var refreshState RefreshState 61
  • 谈谈我对iOS app从编译到完全启动的流程的理解

    从的来说编译分几个阶段 预处理 gt 代码解析 gt 汇编 gt 链接 gt 生成可执行文件 一 预处理的中进行的操作是 1 进行宏替换 2 头文件引入 include import 使用对应 h文件的内容替换这一行 xff0c 所以我们导
  • 使用最新的sdk跑旧的flutter项目遇到的坑总结

    第一次跑一个已经存在的稳定项目却不曾想analysis没报错运行起来xcode却报错 执行flutter 发现android command line没安装 xff0c 立即执行brew install android sdk安装成功后在
  • Vue实现组件间通信

    1 property 在子组件props中定义定属性 xff0c 使用时传递父组件data对象或常量值实现传值通信 2 事件传递 在子组件中通过 emit发送event第一个参数是事件名 xff0c 第二个是消息内容 xff0c 在父组件中
  • 对信号量sem的一些总结

    1 首先来说说信号量和互斥锁的区别 xff1a 信号量用在多线程多任务同步的 xff0c 一个线程完成了某一个动作就通过信号量告诉别的线程 xff0c 别的线程再进行某些动作 xff08 大家都在semtake的时候 xff0c 就阻塞在哪
  • Vue实现双向绑定原理

    在Vue实例构造时将data对象赋值给vue实例之后 xff0c vue会递归遍历data中所有键值对并作为属性赋值到vue实例中 xff0c 利用Object defineProperty 来重新定义属性的set和get函数 xff0c
  • C++ STL总结

    C 43 43 STL分为5部分 容器 xff0c 迭代器 xff0c 空间适配器 xff0c 函数对象 xff0c 泛型算法 xff0c 适配器 一 容器 理解容器的作用 容器的主要作用是用于存储对象 xff08 这里说的对象时指的是包含