C++ 7

ops/2025/2/1 11:51:52/

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.ppmy.cn/ops/154734.html

相关文章

Linux命令汇总

1、帮忙类 --help 直接在当前窗口显示帮助 command --help man 创建新窗口显示帮助 man command 2、目录操作类 2.1、查看目录 ls:以列表方式&#xff0c;查看目录中内容 tree:以树状方式&#xff0c;查看目录中内容 2.2、创建、删除文件及目录 touch&#xff1a;创建…

Myeclipse最新版本 C1 2019.4.0

Myeclipse C1 2019.4.0下载地址&#xff1a;链接: https://pan.baidu.com/s/1MbOMLewvAdemoQ4FNfL9pQ 提取码: tmf6 1.1、什么是集成开发环境? ★集成开发环境讲究-站式开发&#xff0c;使用这个工具即可。有提示功能&#xff0c;有自动纠错功能。 ★集成开发环境可以让软件开…

UE5 GAS RPG Character Classes

在正常的游戏中&#xff0c;我们应该考虑如何去初始化角色属性&#xff0c;并且要给角色分好类型。比如&#xff0c;在我们游戏中&#xff0c;我们如何去初始化小兵的属性&#xff0c;并且还要实现小兵随着等级的增长而增加属性。而且就是小兵也有类型的区分&#xff0c;比如我…

数据结构与算法之字符串: LeetCode 567. 字符串的排列 (Ts版)

字符串的排列 https://leetcode.cn/problems/permutation-in-string/description/ 描述 给你两个字符串 s1 和 s2 &#xff0c;写一个函数来判断 s2 是否包含 s1 的 排列。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 换句话说&#xff0c;s1 的排…

HIVE介绍(五)_hive limit

注意: 1.Hive处理的数据存储在HDFS上 2.hive分析数据的底层处理逻辑是MapReduce 3.执行运行在Yarn上执行 Hive运行原理 Hive为什么要分区&#xff08;partitioned by&#xff09;? 随着系统运行时间越来越长,表的数据量不断增大,通过hive查询通常是"全表扫描"这样就…

Linux 多路转接select

Linux 多路转接select 1. select select() 是一种较老的多路转接IO接口&#xff0c;它有一定的缺陷导致它不是实现多路转接IO的最优选择&#xff0c;但 poll() 和 epoll() 都是较新版的Linux系统提供的&#xff0c;一些小型嵌入式设备的存储很小&#xff0c;只能使用老版本的…

【Flask】在Flask应用中使用Flask-Limiter进行简单CC攻击防御

前提条件 已经有一个Flask应用。已经安装了Flask和redis服务。 步骤1&#xff1a;安装Redis和Flask-Limiter 首先&#xff0c;需要安装redis和Flask-Limiter库。推荐在生产环境中使用Redis存储限流信息。 pip install redis Flask-Limiter Flask-Limiter会通过redis存储限…

2025年01月31日Github流行趋势

项目名称&#xff1a;Qwen2.5项目地址url&#xff1a;https://github.com/QwenLM/Qwen2.5项目语言&#xff1a;Shell历史star数&#xff1a;13199今日star数&#xff1a;459项目维护者&#xff1a;jklj077, JustinLin610, bug-orz, huybery, JianxinMa项目简介&#xff1a;Qwen…