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

C++ 7

vector 底层原理和扩容过程

  1. 底层原理
    ● vector 是 C++ 标准库中的一个容器,可以看作是一个动态数组,它的大小可以根据元素的增加而增长。它通过在堆上分配一段连续的内存空间存放元素,支持时间复杂度为 O(1 ) 的随机访问。
    ● vector 底层维护了三个迭代器和两个变量,这三个迭代器分别指向对象的起始字节位置,最后一个元素的末尾字节和整个 vector 分配空间的末尾字节。两个变量分别是 size 和 capacity ,Size 表示当前存储元素的数量,capacity 表示当前分配空间的大小。当创建一个 vector 对象时,会分配一个初始化大小的空间存放元素,初始化空间可以通过构造函数的参数指定,缺省情况下为 0。当对 vector 容器进行增加和删除元素时,只需要调整末尾元素指针,而不需要移动整个内存块。
  2. 扩容机制
    ● 当添加元素的数量达到当前分配空间的大小时,vector 会申请一个更大的内存块,然后将元素从旧的内存块拷贝到新的内存块中,并释放旧的内存块。 扩容可能导致原有迭代器和指针失效,扩容完成后,容器返回指向新内存区域的迭代器或指针。
    ● vector 扩容的机制分为固定扩容和加倍扩容。
    ○ 固定扩容就是在每次扩容时在原容量的基础上增加固定容量。但是固定扩容可能会面临多次扩容(扩容的不够大)的情况,时间复杂度较高。
    ○ 加倍扩容就是在每次扩容时原容量翻倍,优点是使得正常情况下扩容的次数大大减少,时间复杂度低,缺点是空间利用率低。

push_back()和emplace_back()的区别

push_back()和emplace_back()都是C++标准库容器(如std::vector)中用来添加元素的方法,但它们在添加元素的方式上有所不同:

  1. push_back():
    ○ 语法是container.push_back(value);,传入的是一个值或对象的副本/移动版本。
    ○ 它接受一个元素的副本或移动该元素,然后将其添加到容器的末尾。
    ○ 这个方法需要先构造一个元素的副本或移动构造一个临时对象,然后再将其添加到容器中。
  2. emplace_back():
    ○ 语法是container.emplace_back(args…);,传入的是构造新元素所需的参数列表。
    ○ 它使用就地构造(emplace)的方式,直接在容器的内存空间中构造新元素。
    ○ 这个方法避免了元素的复制或移动操作,因为它直接在容器的末尾空间构造新元素。
  3. 性能:
    ○ emplace_back()通常比push_back()更高效,因为它避免了额外的复制或移动操作。
    ○ 当构造函数需要大量资源时,emplace_back()的优势更加明显。

map dequeu list的实现原理

  1. std:: map
    ● 基于红黑树:std::map 基于一种自平衡的二叉搜索树——红黑树实现。
    ● 有序容器:元素按照键的顺序自动排序,通常是按照小于(<)运算符定义的顺序。
    ● 唯一键:每个键都是唯一的,不允许有重复的键。
    ● 时间复杂度:提供对数时间复杂度 (O(log n)) 的查找、插入和删除操作。
    ● 迭代器:由于 std::map 是基于树的,迭代器在遍历时是有序的。
  2. std::list
    ● 基于双向链表:std::list 是一个双向链表,每个元素都持有指向前一个和后一个元素的指针。
    ● 无序容器:元素在容器中没有特定的顺序。
    ● 插入和删除:提供高效的插入和删除操作,特别是当需要在容器中间插入或删除元素时。
    ● 时间复杂度:提供线性时间复杂度 (O(n)) 的查找操作,但插入和删除可以在 O(1) 时间内完成,前提是已经拥有指向待插入或删除元素的迭代器。
    ● 迭代器:由于 std::list 是线性结构,迭代器在遍历时是顺序的,但不支持随机访问。
  3. std::deque
    ● 基于动态数组:std::deque 是一个基于动态数组的序列容器,可以高效地从两端添加或删除元素。
    ● 允许序列操作:可以快速地在队列的前端和后端添加或删除元素。
    ● 时间复杂度:提供常数时间复杂度 (O(1)) 的前端和后端插入和删除操作。中间插入或删除操作可能需要 O(n) 时间。

map && unordered_map的区别和实现机制

  1. map
    ● 基于红黑树:std::map 基于一种自平衡的二叉搜索树(通常是红黑树)实现,可以保持元素有序。
    ● 有序容器:元素按照键的顺序自动排序,可以通过键值进行有序遍历。
    ● 元素访问:提供对元素的快速查找、插入和删除操作,时间复杂度为 O(log n)。
    ● 唯一键:每个键都是唯一的,不允许有重复的键。
    ● 迭代器稳定性:由于基于树结构,迭代器在遍历时是稳定的,即使容器发生插入或删除操作,迭代器指向的元素也不会改变,除非该元素被删除。
  2. unordered_map
    ● 基于哈希表:std::unordered_map 基于哈希表实现,通过哈希函数将键分布到数组的槽位中。
    ● 无序容器:元素在容器中是无序的,不能按键的顺序进行遍历。
    ● 元素访问:理想情况下,提供平均时间复杂度为 O(1) 的快速查找、插入和删除操作。最坏情况下,性能可能下降到 O(n)。
    ● 允许重复键:实际上,std::unordered_map 不允许有重复的键,因为哈希表的设计不允许两个元素具有相同的哈希值。如果发生哈希冲突,会通过某种方式(如链表或开放寻址)解决。
    ● 迭代器稳定性:由于基于哈希表,迭代器的稳定性不如 std::map。在发生哈希表的重新哈希 (rehashing) 时,迭代器可能会失效。
    ● 遍历顺序与创建该容器时输入元素的顺序是不一定一致的,遍历是按照哈希表从前往后依次遍历的。
  3. 使用场景
    ● 当需要元素有序且对性能有较高要求时,应选择std::map
    ● 当元素的顺序不重要,且需要快速访问元素时,应选择std::unordered_map
  4. 实现机制
    ● std::map 的实现依赖于红黑树的旋转和颜色变换来保持树的平衡,确保操作的时间复杂度。
    ● std::unordered_map 的实现依赖于一个良好的哈希函数来最小化冲突,并通过解决冲突的机制(如链表或开放寻址)来存储具有相同哈希值的元素。

http://www.kler.cn/a/527246.html

相关文章:

  • 【项目初始化】
  • 【Block总结】DynamicFilter,动态滤波器降低计算复杂度,替换传统的MHSA|即插即用
  • Axure PR 9 旋转效果 设计交互
  • Attention--人工智能领域的核心技术
  • Java---猜数字游戏
  • sem_wait的概念和使用案列
  • 【Go语言圣经】第六节:方法
  • Python实现基于TD3(Twin Delayed Deep Deterministic Policy Gradient)算法来实时更新路径规划算法
  • 第05章 17 Contour 过滤器介绍与例子
  • yolov11、yolov8部署的7种方法(yolov11、yolov8部署rknn的7种方法),一天一种部署方法,7天入门部署
  • Java中的getInterfaces()方法:使用与原理详解
  • 寒武纪MLU370部署deepseek r1
  • 【Java计算机毕业设计】基于Springboot的物业信息管理系统【源代码+数据库+LW文档+开题报告+答辩稿+部署教程+代码讲解】
  • 一起学SysML v2规范(01)
  • 【Vite + Vue + Ts 项目三个 tsconfig 文件】
  • Github 2025-01-31Java开源项目日报 Top10
  • 国产之光DeepSeek架构理解与应用分析
  • 【llm对话系统】大模型 Llama 源码分析之 Flash Attention
  • OPENGLPG第九版学习
  • Baklib对比其他知识管理工具的优势及应用效果全面分析
  • 数模测评:doubao1.5>deepseek-v3>gpt-o1
  • C# 实现 “Hello World” 教程
  • 37. RGBLCD实验
  • 最新Python大数据之Python基础【十】学生管理系统面向对象版_python面向对象学生管理系统
  • JAVA实战开源项目:网上购物商城(Vue+SpringBoot) 附源码
  • 随笔 | 写在一月的最后一天