【理解STL】

目录

  • 一、STL的概念
    • 1、STL的定义
    • 2、STL的组成
  • 二、容器
    • 1、容器的定义及作用
    • 2、string类(非容器)
    • 3、vector容器
    • 4、set容器
    • 5、queue容器
    • 6、priority_queue容器
    • 7、stack容器
    • 8、deque容器
    • 9、map容器
    • 10、pair容器
    • 11、bitset容器
    • 12、map和set的区别
    • 13、vector和list的区别
  • 三、分配器(allocaotr)
  • 四、迭代器(iterator)
    • 1、迭代器的概念
    • 2、迭代器和指针的区别
    • 3、迭代器产生的原因

一、STL的概念

1、STL的定义

STL是惠普实验室开发的一系列标准化组件的统称。STL的一个基本理念就是将数据和操作分离,数据由容器加以管理,操作则由可定制的算法完成,迭代器在两者之间充当“黏合剂”。

2、STL的组成

STL主要由六个部分组成:分配器(allocator)、配接器(adapters)、容器(containers)、迭代器(Iterator)、仿函数(functors)、算法(algorithm)。

分配器给容器分配存储空间,算法通过迭代器获取容器中的内容,仿函数可以协助算法完成各种操作,配接器用来套接适配仿函数。

二、容器

1、容器的定义及作用

容器是存储其他对象的对象,它存储的对象可以是自定义数据类型的对象,也可以是内置数据类型的对象。这些被存储的对象必须是同一种数据类型,它们归容器所有,称为容器的元素。当容器失效时,容器中的元素也会失效。容器本身包含了处理这些数据的方法。另外,容器最重要的优点就是它可以扩展自身的大小。
从实现角度来看,STL容器是一种类模板(class template)。
STL容器是将运用最广泛的一些数据结构实现出来,数组(array)、链表(list)、树(tree)、栈(stack)、队列(queue)、集合(set)、映射表(map),根据数据在容器中的排列特性,分为序列式容器和关联式容器。

序列式容器:容器元素在容器中的位置是由元素进入容器的时间和地点来决定。有:vector容器、deque容器、list容器、stack容器、queue容器。

关联式容器:是指容器已经有了一定的规则,容器元素在容器中的位置由我的规则来决定。是可以存储键-值对的容器,使用键来快速检索值,里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器的效率高,有:set/multiset容器、map/multimap容器。

2、string类(非容器)

string类与STL容器有很多相似的操作,C++中的string类相当于是字符数组,但是其更方便于我们的操作,不需要在输入之前初始化字符数组的容量,节省了空间。

3、vector容器

vector是变长数组(vector内部使用动态内存分配,可以根据需要动态增加或减少其占用的内存空间,这样可以在运行时接喊个空间,因为vector只会使用实际需要的内存空间),在堆上分配空间,支持随机访问(由于vector内部使用数组来存储元素,因此可以通过索引直接访问任意位置的元素),不支持在任意位置O(1)插入。为了保证效率,元素的增删都应该在末尾进行(在中间或者开头进行插入操作是O(n)的,因为涉及到元素的移动和内存的重新分配)。

vector的用法举例:

#include<vector>

/*vector 生成*/
vector<int> vct(3);//数组中有3个元素,不指定的情况下默认为0
vector<int>vct(3,5);//数组中有3个元素,全是5
vector<int>vct{123};//数组中的元素为1,2,3

/*vector 头尾*/
vector.front();//第一个元素
vector.back();//最后一个元素

/*vector 迭代器*/
vector<int>::iterator iter //一个vector的迭代器
vct.begin()//指向vct中第一个元素位置的迭代器
vct.end()//指向vct中最后一个元素位置的迭代器

/*vector 插入*/
vct.push_back(1);//在尾部插入一个1
vct.insert(vct.begin(),1);//在指定位置前面插入一个元素1

/*vector 删除*/
vct.pop_back();//删除vct中最后一个元素
vct.erase(vct.begin());//删除指定位置的元素
vct.erase(vct.begin()+1, vct.end()-2);//删除vct中第二个元素到倒数第三个元素中的所有元素(包括第二个和倒数第三个)

/*vector 容量*/
vct.size()

/*vector 遍历*/
for(int i = 0;i<vct.size();i++)//索引遍历
for(vector<int>::iterator iter = vct.begin(); iter != vct.end();iter++)//迭代器遍历
for(auto &x :vct)//迭代器的另一种便捷遍历方法

/*vector 排序*/
sort(vct.begin(),vct.end());

/*vector 查找*/
vct.find(2);//从前往后,找元素2,若找到,则返回指向该处的迭代器,若没找到,则返回vct.end()

/*vector 某元素的个数*/
vct.count(2);//返回容器中2的个数

/*vector 判空*/
vct.empty()//返回布尔值

/*vector 清空*/
vct.clear();

4、set容器

头文件主要包括set和multiset两个容器,分别是“有序集合”和“有序多重集合”,即前者的元素不能重复,而后者可以包含若跟个相等的元素,两者都会将其容器内的元素按照从小到大自动排序。set内部使用二叉搜索树(红黑树,RB Tree)数据结构来存储元素,并根据元素的键值进行自动排序。

set的用法如下:

#incude<set>

/*set生成*/
set<int> st;

/*set 迭代器*/
set<int>::iterator iter
st.begin()
st.end()

/*set 插入*/
set.insert(2);//插入一个为值为2的元素

/*set 删除*/
st.erase(st.begin());//删除迭代器指向元素
st.erase(2);//删除所有为2的元素

/*set 容量*/
st.size();

/*set 查找*/
st.find(2);//从前往后找为2的元素,若找到,返回指向该处的迭代器,反之,返回迭代器st.end()
st.lower_bound(x);//二分查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器
st.upper_bound(x);//二分查找大于等于x的元素中最大的一个,并返回指向该元素的迭代器、

/*set 某元素的个数*/
st.count(2);//返回容器里2的个数

/*set 判空*/
st.empty();//返回布尔值

/*set 清空*/
st.clear();

5、queue容器

头文件queue主要包括循环队列queue和优先队列priority_queue两个容器,其中queue容器相当于队列,满足先进先出的原则,即队尾进、队首出。

queue的用法举例:

#include<queue>

/*queue 生成*/
queue<int> q;

/*queue 头尾*/
q.front();
q.back();

/*queue 插入*/
q.push();//在队首插入一个元素

/*queue 删除*/
q.pop();//在队首删除一个元素

/*queue 容量*/
q.size();

/*queue 判空*/
q.empty()

6、priority_queue容器

priority_queue容器相当于大根堆(或者小根堆),大根堆每次堆项是最大元素,小根堆每次堆项是最小元素。

priority_queue用法举例:

#include<queue>

/*priority_queue 生成*/
priority_queue<int> pq;//大根堆
priority_queue<int,vector<int>,greater<int>> pq;//小根堆

/*priority_queue 插入*/
pq.push(2);//把元素2插入堆

/*priority_queue 删除*/
pq.pop();//删除堆顶的元素

/*priority_queue 堆项*/
pq.top();//返回堆顶元素

/*priority_queue 容量*/
pq.size();

/*priority_queue 判空*/
pq.empty()

7、stack容器

stack容器相当于栈,满足先进后出的原则,即插入和删除都只能在栈顶操作。

stack用法举例:

#include<stack>

/*stack 生成*/
stack<int> sk;

/*stack 插入*/
sk.push(1);//把元素1放入栈顶

/*stack 删除*/
sk.pop();//删除栈顶元素

/*stack 栈顶*/
sk.top();//返回栈顶元素

/*stack 容量*/
sk.size();

/*stack 判空*/
sk.empty()

8、deque容器

双端队列deaue容器是一个支持在两端高效插入或删除元素的连续性存储空间,它就像是vector和queue的结合。与vector相比,deque在头部增删元素仅需要O(1)的时间,与queue相比,deque像数组一样支持随机访问。

deque的用法举例:

#include<deque>

/*deque 生成*/
deque<int> dq;

/*deque 迭代器*/
deque<int>::iterator iter
dq.begin()
dq.end()

/*deque 插入*/
dq.push_front(1);//在头部插入元素1
dq.push_back(1);//在尾部插入元素1

/*deque 删除*/
dq.pop_front();//删除头部元素
dq.pop_back();//删除尾部元素

/*deque 容量*/
dq.size();

/*deque 判空*/
dq.empty()

/*deque 头尾*/
dq.front();
dq.back();

/*deque 清空*/
dq.clear();

9、map容器

map容器是一个键值对key-value的映射,其内部实现是一颗以key为关键码的红黑树。map的key和value可以是任意类型。unordered_map的底层结构是哈希表。

map的用法举例:

#include<map>

/*map 生成*/
map<key_type, value_type> name;
map<int, int> mp;

/*map 迭代器*/
map<int, int>::iterator iter
mp.begin()
mp.end()

/*map 键值*/
iter->first//key
iter->second//value

/*map 插入*/
mp[2] = 5;//2是key,5是value
mp.insert(pair<int, int>(2,5));//insert一个pair

/*map 删除*/
mp.erase(iter);//删除迭代器所指的键值对

/*map 容量*/
mp.size()

/*map 查找*/
mp.find(2);//从前往后,找元素2,若找到,则返回指向该处的迭代器,反之,返回迭代器mp.end()

/*map 某元素的个数*/
mp.count(2);

/*map 判空*/
mp.empty()

/*map 清空*/
mp.clear();

10、pair容器

pair容器相当于将两份数据打包为一对,两份数据的数据类型任意,多与其他容器混合使用,单独使用的情况比较少。
pair的用法举例:

#include<utility>

/*pair 生成*/
pair<int,int> pr = make_pair(0,1);

/*pair 两个值*/
pr.first
pr.second

/*pair 多与其他容器混合使用*/
set<pair<int,int>> st;
vector<pair<int,int>> vct(mp.begin(), mp.end());

11、bitset容器

bitset容器相当于是0/1数组,其方便之处是可以直接按位进行位运算,但是要注意下标从小到大依次存低位到高位,是逆序的。

#include<bitset>

/*bitset 生成*/
bitset<4> bt;//生成4位二进制数,初始化为0000
bitset<8> bt(12);//生成8位二进制数,且将十进制数12转化为二进制数存入其中,12的二进制数为:0000 1100
bitset<8> bt(str);//str可以是只有0/1的字符串或字符数组

/*bitset 位相关运算*/
bt1 |= bt2;//按位或
bt1 &= bt2;//按位与
bt1 ^= bt2;//按位异或
bt1 =~ bt2;//按位取反
bt1 <<= x;//左移x位

bt.test(x)//判断第x个位置是0还是1,也就是输出第x个位置,注意逆序

bt.flip();//将二进制每一位取反
bt.flip(x);//将二进制第x位取反
bt.set();//将二进制每一个位置都置为1
bt.set(x);//将二进制第x个位置1
bt.reset();//将二进制每一个位置都置0
bt.reset(x);//将二进制第x个位置置0

/*bitset 容量*/
bt.size()//二进制数组的长度,也就是生成时定义的长度

/*bitset 某元素的个数*/
bt.count();//查询二进制数组中1的个数

/*bitset 转化字符串*/
string str = bt.to_string();//将二进制数组转化为字符串

12、map和set的区别

  1. map中的元素是key-value(关键字-值)对:关键字起到索引的作用,值则表示与索引相关联的数据;set与之相对的就是关键字的简单集合,set中每个元素只包含一个关键字;
  2. set的迭代器是const的,不允许修改元素的值;map允许修改value,但不允许修改key。其原因是map和set是根据关键字排序来保证其有序性的,如果允许修改key的话,那么首先需要删除该键,然后调节平衡,再插入修改后的键值,调节平衡,如此一来,严重破坏了map和set的结构,导致iterator失效,不知道应该指向改变前的位置还是改变后的位置,所以STL中将set的迭代器设置为const,不允许修改迭代器的值;而map的迭代器则不允许修改key的值,允许修改value的值。
  3. map支持下标操作,set不支持下标操作。map可以用key做下标,map的下标运算符[]将关键码作为下标去执行查找,如果关键码不存在,则插入一个具有该关键码和mapped_type类型默认值的元素到map容器中,因此下标运算符[]在map中应谨慎使用,在const_map中不能用,只希望确定某一个关健值是否存在而不希望插入元素时也不能用,mapped_type类型没有默认值也不应该使用。如果find能解决需求,尽量使用find。

13、vector和list的区别

1、vector
连续存储的数组、动态数组、在堆上分配空间
底层实现:数组
两倍容量增长
vector增加(插入)新元素时,如果未超过当时的容量,还有剩余的空间,则直接添加到最后(插入指定位置),然后调整迭代器;若没有剩余空间,则会重新配置原有元素个数的两倍空间,然后将原空间元素通过复制的方式初始化新空间,再向新空间增加元素,最后析构并释放原空间,之前的迭代器会失效。
性能:
访问:O(1)
插入:在最后插入(空间够):很快
在最后插入(空间不够):需要内存申请和释放,以及对之前数据进行拷贝
在中间插入(空间够):内存拷贝
在中间插入(空间不够):需要内存申请和释放,以及对之前数据进行拷贝
删除:删除末尾:很快
在中间删除:内存拷贝
适用场景:经常随机访问,且不经常对非尾节点进行插入删除
2、list
动态链表、在堆上分配空间、每插入一个元素都会分配空间,每删除一个元素都会释放空间
底层:双向链表
性能:
访问:随机访问性能很差,只能快速访问头尾节点
插入:很快,一般是常数开销
删除:很快,一般是常数开销
适用场景:经常插入删除大量数据
3、区别

  1. vector底层实现是数组,list是双向链表;
  2. vector支持随机访问,list不支持;
  3. vector是顺序内存,list不是;
  4. vector在中间进行插入删除需要进行内存拷贝,list不需要;
  5. vector一次性分配好内存,不够时才进行两倍扩容;list每次插入新节点都会进行内存申请;
  6. vector随机访问性好,插入删除性能差;list随机访问性差,插入删除性能好。
  7. 适用场景不同,vector适用于需要高效进行随机访问而不在乎插入和删除的效率的场景;list适用于需要高效进行插入和删除而不关心随机访问效率的场景。

三、分配器(allocaotr)

STL的空间适配器用于封装STL容器在内存管理上的底层细节。在C++中,其内存配置和释放如下:

new运算分为两个阶段:(1)调用::operator new配置内存(2)调用对象构造函数构造对象内容
delete运算分为两个阶段:(1)调用对象析构函数(2)调用::operator delete释放内存

为了精密分工,STL allocaotr将两个阶段操作区分开来,内存配置由alloc::allocate()负责,内存释放由alloc::deallocate()负责;对象构造由::construct()负责,对象析构由::destroy()负责。

同时为了提升内存管理的效率,减少申请小内存造成的内存碎片化的问题,SGI STL采用了两级配置器,当分配的空间大小超过128B时,会使用第一级空间配置器;当配置的空间大小小于128B时,将使用第二级空间配置器。第一级空间配置器直接使用malloc()、realloc()、free()函数进行内存的分配和释放,而第二级空间适配器则采用了内存池技术,通过空闲链表来管理内存

四、迭代器(iterator)

1、迭代器的概念

iterator模式又称为custor(游标)模式,用于提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。换个更容易理解的说法:iterator模式是运用于聚合对象的一种模式,通过运用该模式,我们可以在不知道对象内部表示的情况下,按照一定的顺序(由iterator提供的方法)访问聚合对象中的各个元素。

由于iterator模式的以上特性:与聚合对象耦合,在一定程度上限制了它的广泛运用,一般仅用于底层聚合支持类,如STL的list、vector、stack等容器类及ostream_iterator等扩展iterator。

2、迭代器和指针的区别

迭代器不是指针,是类模版,表现得像指针。它只是模拟了指针的一些功能,通过重载了指针的一些操作符->、、++、–等迭代器封装了指针,是一个“可遍历的STL(Standard Template Library)容器内全部或部分元素”的对象,本质是封装了原生指针,是指针概念的一种提升(lift),提供了比指针更高级的行为,相当于一种只能指针,它可以根据不同类型的数据结构来实现不同的++,–等操作。
迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用
取值后的值,而不能直接输出其自身。

3、迭代器产生的原因

iterator类的访问方式就是把不同集合类的访问逻辑抽象出来,使得不用暴露集合内部的结构而达到循环遍历集合的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/783576.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Unity2D 2022:Particle System】添加拾取粒子特效

一、创建粒子特效游戏物体 二、修改粒子系统属性 1. 基础属性 &#xff08;1&#xff09;修改发射粒子持续时间&#xff08;Duration&#xff09;为3s &#xff08;2&#xff09;取消勾选循环&#xff08;Looping&#xff09; &#xff08;2&#xff09;修改粒子存在时间&…

星网安全产品线成立 引领卫星互联网解决方案创新

2024年6月12日&#xff0c;盛邦安全&#xff08;688651&#xff09;成立星网安全产品线&#xff0c;这是公司宣布全面进入以场景化安全、网络空间地图和卫星互联网安全三大核心能力驱动的战略2.0时代业务落地的重要举措。 卫星互联网技术的快速发展&#xff0c;正将其塑造为全球…

leetcode:编程基础0到1

文章目录 交替合并字符串str.length();StringBuilder类型 ,toString()append() &#xff0c;chatAt()题目描述 交替合并字符串 str.length(); 输出字符串str的长度 StringBuilder类型 ,toString() append() &#xff0c;chatAt() 题目描述 class Solution {public String …

(译文)IRIG-B对时编码快速入门

原文 PDF&#xff1a;https://ww1.microchip.com/downloads/aemDocuments/documents/FTD/tekron/tekronwhitepapers/221223-A-guide-to-IRIG-B.pdf IRIG-B3 概论 Inter-Range Instrument Group 时间码&#xff08;简称IRIG&#xff09;是一系列标准时间码格式。用于将时间信…

俄罗斯VK Ads开户充值全流程!VK如何开户?VK如何注册?VK广告

在俄罗斯&#xff0c;VK&#xff08;VKontakte&#xff09;是一个广受欢迎的社交媒体平台&#xff0c;对于寻求进入该市场的企业来说&#xff0c;进行VK广告推广是一条有效途径。 首先&#xff0c;你需要明确自己要推广的产品或服务&#xff0c;并且确定目标市场和受众。 由于…

1.8.0-矩阵乘法的反向传播-简单推导

1相关资料 之前分享过一个博客里面写的&#xff0c;我们大致了解并记住结论的博客&#xff1a;【深度学习】7-矩阵乘法运算的反向传播求梯度_矩阵梯度公式-CSDN博客&#xff1b;这里再分享一下自然语言处理书上关于这部分的推导过程&#xff1a;3-矩阵相乘-梯度反向传播的计算…

如何下载jmeter旧版本

如何下载jmeter旧版本 推荐先用旧版本做好测试基本操作&#xff0c;因为高版本不适合做压力测试&#xff0c;需要证书&#xff0c;有点麻烦。 1.百度或直接打开jmeter官网&#xff1a;https://jmeter.apache.org/ 2.向下拖到Archives一栏&#xff0c;点击Apache Jmeter archi…

ICC2:ignore pin的设置

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 相关文章链接:

OS Copilot测评

1.按照第一步管理重置密码时报错了,搞不懂为啥?本来应该跳转到给的那个实例的,我的没跳过去 2.下一步重置密码的很丝滑没问题 3安全组新增入库22没问题 很方便清晰 4.AccessKey 还能进行预警提示 5.远程连接,网速还是很快,一点没卡,下载很棒 6.替换的时候我没有替换<>括…

六、快速启动框架:SpringBoot3实战-个人版

六、快速启动框架&#xff1a;SpringBoot3实战 文章目录 六、快速启动框架&#xff1a;SpringBoot3实战一、SpringBoot3介绍1.1 SpringBoot3简介1.2 系统要求1.3 快速入门1.4 入门总结回顾复习 二、SpringBoot3配置文件2.1 统一配置管理概述2.2 属性配置文件使用2.3 YAML配置文…

调制信号识别系列 (一):基准模型

调制信号识别系列 (一)&#xff1a;基准模型 说明&#xff1a;本文包含对CNN和CNNLSTM基准模型的复现&#xff0c;模型架构参考下述两篇文章 文章目录 调制信号识别系列 (一)&#xff1a;基准模型一、论文1、DL-PR: Generalized automatic modulation classification method b…

如何优化 PostgreSQL 中对于复杂数学计算的查询?

文章目录 一、理解复杂数学计算的特点二、优化原则&#xff08;一&#xff09;索引优化&#xff08;二&#xff09;查询重写&#xff08;三&#xff09;数据库配置调整&#xff08;四&#xff09;使用数据库内置函数的优势 三、具体的优化方案和示例&#xff08;一&#xff09;…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【加密导入密钥(C/C++)】

加密导入密钥(C/C) 以加密导入ECDH密钥对为例&#xff0c;涉及业务侧加密密钥的[密钥生成]、[协商]等操作不在本示例中体现。 具体的场景介绍及支持的算法规格。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 设备A&#xf…

【机器学习】——决策树模型

&#x1f4bb;博主现有专栏&#xff1a; C51单片机&#xff08;STC89C516&#xff09;&#xff0c;c语言&#xff0c;c&#xff0c;离散数学&#xff0c;算法设计与分析&#xff0c;数据结构&#xff0c;Python&#xff0c;Java基础&#xff0c;MySQL&#xff0c;linux&#xf…

PHP宝藏神器多功能投票系统源码小程序

&#x1f389;发现宝藏神器&#xff01;一键解锁“多功能投票小程序”的无限可能✨ &#x1f308; 开篇安利&#xff1a;告别繁琐&#xff0c;拥抱高效&#xff01; Hey小伙伴们&#xff0c;是不是经常为组织活动、收集意见而头疼不已&#xff1f;&#x1f92f; 今天就要给大…

迭代器模式(大话设计模式)C/C++版本

迭代器模式 C #include <iostream> #include <string> #include <vector>using namespace std;// 迭代抽象类,用于定义得到开始对象、得到下一个对象、判断是否到结尾、当前对象等抽象方法&#xff0c;统一接口 class Iterator { public:Iterator(){};virtu…

Android约束布局的概念与属性(2)

目录 3&#xff0e;链式约束4&#xff0e;辅助线 3&#xff0e;链式约束 如果两个或以上控件通过下图的方式约束在一起&#xff0c;就可以认为是他们是一条链&#xff08;如图5为横向的链&#xff0c;纵向同理&#xff09;。 图5 链示意图 如图5所示&#xff0c;在预览图中选…

面向计算机类岗位人才需求分析研究 --基于前程无忧招聘网站的数据经验证据

1 引言 随着智能互联网的快速发展和一系列的技术变革&#xff0c;从而推动全国各行业进行政策的调整、资源的共享、产业的升级和信息的创新。结合国家的战略&#xff0c;政府明确的指出&#xff0c;建设国家大数据池意义重大。通过海量数据的支持与算法优化后的计算能力&#…

水果商城系统 SpringBoot+Vue

1、技术栈 技术栈&#xff1a;SpringBootVueMybatis等使用环境&#xff1a;Windows10 谷歌浏览器开发环境&#xff1a;jdk1.8 Maven mysql Idea 数据库仅供学习参考 【已经答辩过的毕业设计】 项目源码地址 2、功能划分 3、效果演示

Perforce发布白皮书,解读电动汽车初创公司如何加速进入市场并降低软件开发中的风险和成本

电动汽车&#xff08;EV&#xff09;领域的初创企业正迅速崛起&#xff0c;创新速度显著加快。然而&#xff0c;随着消费者对电动汽车需求的激增&#xff0c;老牌汽车制造商正加速进军这一市场&#xff0c;加剧了行业竞争。为在竞争中生存并发展&#xff0c;电动汽车初创企业必…