当前位置: 首页 > news >正文

C++方向知识汇总(三)

关于Vector

1.vector是什么?常用场景?底层用了什么数据结构?

答:

vector是动态数组,支持快速随机访问、适合频繁读取、尾部增删的场景(如有序数组遍历)

底层是基于连续分配的数组,类似于动态扩容数组,采用三个指针实现

2.vector的扩容机制是怎样的?扩容时会发生什么?

答:

默认按1.5倍扩容,vs下是2倍

扩容分三步:申请新内存、拷贝原数据到新内存、释放原内存(原迭代器失效)

3.vector的reserve和resize区别?

答:

reserver进行扩容,不改变size个数、提前预留空间

resize改变size个数,可能触发扩容,多余元素初始化0,小于原size则销毁多余元素,容量不变

4.请解释vector容器和他的特点?

答:

vector是c++标准模板库STL里的容器,就是一个动态数组、空间不够自动扩容、支持随机访问、可通过索引直接访问元素、事件复杂度O1,可以高效尾插尾删、中间和开头效率低

5.vector如何保证元素的连续存储

答:

使用动态分配的数组空间存储元素,分配空间在堆上,是连续的,元素不足扩容时,还是使用的连续空间,把旧数据拷贝到新连续空间上。保证了数据的连续存储

6. vector的push_back和emplace_back有什么区别?

答:

push_back需要传入对象,emplace_back可以直接传入对象的参数

push_back会触发拷贝构造,emplace_back直接在容器原地构造

push_back即使会触发移动构造,效率也不及emplace_back

7.vector的增删都是怎么做的?为什么是1.5倍或2倍扩容?

答:

push_back和insert插入 pop_back和erase删除

1.5倍或者2倍是为了防止频繁扩容,也为了减少内存浪费,1.5倍相比2倍内存浪费更少

8.vector扩容后,迭代器会怎样?

答:

所有迭代器失效

9.vector和数组有什么区别?

答:

数组大小固定,编译器确定大小,vector大小自动扩容

数组在栈上开辟空间,或者动态数组堆上,vector在堆上,自动管理内存

10.vector的底层数据结构是什么?

答:

vector的底层数据结构是动态数组

11.如何避免vector频繁扩容?

答:

提前预留空间使用reserve,避免频繁扩容

关于List

1.list的底层结构是什么?有什么特点?

答:

list底层是双向循环链表,每个节点包括数据和两个指针(前驱节点和后驱节点)

特点:内存空间不是连续的,不需要提前开辟固定大小空间
插入删除速度快,时间复杂度O1,但不支持随机访问,需从头遍历,时间复杂度On
删除只会当前迭代器失效,不影响其他迭代器

2.vector和list的核心区别是什么?各自适用场景?

答:

vector 动态数组 || 随机访问O1 || 中间插删效率低On || 可能频繁扩容 || 可能迭代器失效
list 双向链表| | 不支持随机访问On || 中间插删效率高O1 || 不存在频繁扩容 || 仅当前迭代器失效

vector适合需要频繁访问的,以尾插尾删为主的(如存储数据然后频繁查询)
list适合需要中间开头频繁插入删除的,无需随机访问的场景(如链表操作、队列)

3.list有哪些常用成员函数?与vector相比有什么特殊点?

答:

push_back push_front pop_back pop_front  insert erase splice sort

特殊:有头插头删 有splice方法 自带sort成员函数,因为不支持随机访问无法使用全局STL算法
,需使用自身的排序,时间复杂度Onlogn

4.list的迭代器为什么是双向迭代器,而不是随机访问迭代器?

答:

vector是连续数组,迭代器可通过+n -n 直接跳转

list是双向链表,节点地址不在一块,不连续,只能通过++ -- 来移动,每次一步,因为要双向迭代器

5.list如何避免内存碎片?与vector相比内存效率如何?

答:

list每个节点单独分配内存、释放也是单独释放、频繁插入删除可能导致小量内存碎片

vector是大块连续内存,扩容可能一次性释放旧内存、内存碎片相对较少

总体而言,list内存利用率低,每个节点还需要存储前驱后驱、但没有vector扩容时的峰值内存消耗

6.如何实现一个线程安全的list?

答:

线程安全需保证多线程对list的操作不需要资源竞争

方案:对List的所有操作加锁,确保某一时刻只有一个在访问
用读写锁,运行多个线程访问,不允许多个修改写入



关于map/set/unordered_map/unordered_set

1.map/set的底层数据结构是什么?为什么选择这种结构?

答:

底层是红黑树,一种近似平衡的二叉搜索树

选择它是因为有序性和高效率操作

红黑树通过严格的规则、使插入删除查找操作都在Ologn时间复杂度

相比AVL树,旋转更少、性能更佳

红黑树中序遍历是有序的,满足map/set的要求

2.map/set、multimap、multiset的核心区别是什么?

答:

map 存储键值对 key唯一 不允许重复

multimap key可以不唯一,可以重复,但是不支持[]了,因为key重复了,无法确定找那个

set 存储键值对,但key=value 不可以重复

multiset 可以重复,可能存储多个相同元素

简单来说:map/set 有去重的功能

3.与哈希容器的对比

答:

map 红黑树 有序 增删查Ologn 内存占用较低(仅存储数据和指针) 删除不影响其他迭代器

unordered_map 哈希表 无需 增删查O1,查找最坏On 内存占用较高(哈希表需预留空间) 扩容所有迭代器失效

哈希追求极致效率、适合不关心有序的场景(如缓存,哈希表计数等)

4.为什么unordered_map的查找效率平均O1,最坏On?

答:

unordered_map底层是哈希表,有时候会产生哈希冲突,大量的哈希冲突,导致几个数据被存在一个长链表/桶中,需遍历链表 时间复杂度就上去了

5.如何解决哈希冲突?

答:

可以优化,采用开链法,冲突时在链表后追加节点、链表超过指定长度转为红黑树

动态扩容,根据负载因子,超过阈值如0.7,自动扩容哈希表,重新哈希映射所有元素

6.map的insert和[]操作有什区别?

答:

两者都可以插入键值对,但是:

insert 当key不存在时插入,若存在不做操作,返回一个pair

[] 当key不存在时插入、新键值对、若存在直接修改对应的value

想要插入但不覆盖用insert,想要插入或者更新用[]

7.如何高效遍历map/set?迭代器有什么特点?

答:

迭代器遍历或者范围for遍历 

特点:是双向迭代器、因为支持++ --   不支持+n -n,跟list一样

删除只导致当前迭代器失效,不影响其他的

8.当自定义类型作为map的key或者set的元素时,需要做什么?

答:

需要自定义比较规则,因为需要排序,根据规则插入

在自定义类型中重载< 或者自定义一个仿函数

关于容器适配器stack、queue、priority_queue、deque

1. 容器适配器 stack、queue、priority_queue 的底层默认容器是什么?能否更换底层容器?

答:

stack 基于deque实现(也可以vector或list)

queue 基于 deque实现(也可以list)

priority_queue 基于vector实现(配合堆算法,也可以使用deque)

2. stack 和 queue 为什么默认选择 deque 作为底层容器,而不是 vector 或 list?

答:

平衡性的结果 stack和queue都需要高效的尾部头部插入删除 deque刚好满足 list缓存利用低 所以选用deque

deque分段连续内存、扩容成本比vector低

list节点不连续、缓存利用率低

http://www.dtcms.com/a/326122.html

相关文章:

  • 面试实战 问题二十三 如何判断索引是否生效,什么样的sql会导致索引失效
  • git:分支
  • 3Ds Max的魔改利器:RailClone - 程序化建模的革命者
  • MySQL 经典练习 50 题(完美解答版,提供解题思路)
  • Spring Framework源码解析——DisposableBean
  • Oracle数据库中的Library cache lock和pin介绍
  • Java多线程并发控制:使用ReentrantLock实现生产者-消费者模型
  • js异步操作 Promise :fetch API 带来的网络请求变革—仙盟创梦IDE
  • 机器翻译:Bahdanau注意力和Luong注意力详解
  • 【浮点数存储】double类型注意点
  • 理解LangChain — Part 3:链式工作流与输出解析器
  • Notepad--:国产跨平台文本编辑器,Notepad++ 的理想替代方案
  • 写一篇Ping32和IP-Guard的对比,重点突出Ping32
  • 循环控制:break和continue用法
  • 鸿蒙flutter项目接入极光推送
  • Java项目基本流程(三)
  • Orange的运维学习日记--38.MariaDB详解与服务部署
  • linux安装和使用git
  • Elasticsearch 官方 Node.js 从零到生产
  • docker部署elasticsearch-8.11.1
  • 网络的基本概念、通信原理以及网络安全问题
  • YOLOv6深度解析:实时目标检测的新突破
  • 时序数据库为什么选IoTDB?
  • 爬虫与数据分析结合案例
  • STM32 HAL驱动MPU6050传感器
  • p6spy和p6spy-spring-boot-starter的SpringBoot3集成配置
  • 高性能Web服务器
  • java基础概念(二)----变量(附练习题)
  • Go 语言三大核心数据结构深度解析:数组、切片(Slice)与映射(Map)
  • Unity插件DOTween使用