六安市网站建设_网站建设公司_网站制作_seo优化
2025/12/18 16:18:45 网站建设 项目流程

前言

本文将带你穿越C++容器的迷雾森林:从vector动态扩容的数学玄机,到emplace_back比push_back快在哪的微观真相;从红黑树与哈希表的世纪对决,到连续存储背后的内存博弈。无论你是渴望通过大厂面试的技术追梦人,还是致力于优化千万级代码的性能极客,这里都有你意想不到的硬核干货。


目录

1. STL容器了解那些

简要回答

详细回答

STL的特点如下

知识扩展:

2. vector和array的使用场景分别是什么?

2.1. 基本介绍

2.2. std :: vector 使用场景

2.3. std :: array使用场景

2.4. 对比传统数组的优势

3. 描述一下vector是如何保证数组连续存储的吗?

4. 当vector的空间不足以容纳更多的元素时,它是如何扩容的?

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

简要回答

详细回答

知识扩展:


1. STL容器了解那些

简要回答

C++STL中主要有三类容器:

  • 顺序容器(Sequence Containers):如vector、list、deque、array、forward_list
  • 关联容器(Associative Containers):如set、map、multiset、multimap
  • 无序容器(Unordered Containers)哈希容器:如unordered_map、unordered_set、unordered_multimap、unordered_multiset

此外,STL还包括配套的迭代器、算法、仿函数、适配器等组件。


详细回答

STL容器可以分为三大类:

  • 序列容器:维护元素的线性序列
  1. vector(动态数组,支持快速随机访问)
  2. deque(双端队列,两端高效插入和删除)
  3. forward_list(单向链表,任意位置高效插入和删除)
  4. array(固定大小数组,更安全的原生数组替代)
  • 关联容器:基于键值对的有序存储
  1. set/multiset(有序唯一/非唯一键集合)
  2. map/multimap(有序键值对集合,键唯一/非唯一)
  • 无序关联容器:基于哈希表的存储
  1. unordered_set/unordered_multiset
  2. unordered_map/unordered_multimap

每种容器在时间复杂度、内存布局和使用场景下有所不同。


STL的特点如下

序列容器

容器特点
vector动态数组,随机访问快,尾部插入快
list双向链表,任意位置插入/删除快
deque双端队列,头尾都能快速插入/删除
array固定大小数组(C++11)
forward_list单向链表(C++11)

关联容器(有序,就红黑树)

容器特点
set唯一元素自动排序
multiset元素允许重复
map键值对,键唯一
multimap键值对,键可重复

无序关联容器(基于哈希表,C++11)

容器特点
unordered_set无序唯一集合
unordered_map无序键值对
unordered_multiset无序可重复集合
unordered_multimap无序可重复键值对

代码实例:

#include <iostream> #include <vector> #include <map> #include <set> #include <unordered_map> #include <list> using namespace std; int main() { vector<int> vec = {1, 2, 3}; vec.push_back(4); // 动态数组 list<int> lst = {10, 20, 30}; lst.push_front(5); // 双向链表 set<int> s = {5, 2, 3, 2}; // 自动去重排序 map<string, int> m = {{"Tom", 90}, {"Jerry", 85}}; // 字典 unordered_map<string, int> um; um["apple"] = 3; um["banana"] = 5; // 哈希表 return 0; }

知识扩展:

STL的底层结构:

vector、deque动态数组
list、forward_list链表
set、map红黑树
unordered_*哈希表

性能差异:

  • vector 随机访问快,但是插入慢(插入过程中需要移动元素)
  • list 插入快,但是不支持随机访问
  • map/set 查找、插入都是O(logN),但是是有序的
  • unordered_map 查找、插入都是O(1)的平均复杂度

使用场景:

  • vector(需要随机访问,动态扩容的情况,如图像处理、线性缓存)
  • list(频繁插入删除数据的场景,如编辑器撤回栈)
  • map/unordered_map:查找、计数、字典、配置解析,如记录访问次数
  • set(需要去重、唯一性判断,如用户ID集合)
  • deque(实现滑动窗口算法,双端队列缓存)

2. vector和array的使用场景分别是什么?

2.1. 基本介绍

特性std::vectorstd::array(C++11 引入)
大小动态可变固定不变(编译时确定)
内存分配堆(动态分配)栈(静态分配)
标准库支持C++98 起就有C++11 起引入
元素访问支持下标访问和迭代器同样支持
效率稍慢(涉及动态分配)更快(在栈上分配,无需额外开销)

2.2. std :: vector 使用场景

适用于元素数量运行时变化、在末尾频繁插入删除、需要自动扩容的场景:

  • 动态读取用户输入或文件内容
  • 使用STL算法是需要可变容器(如排序)
  • 实现堆栈、队列、图等动态结构
#include <iostream> #include <vector> int main() { std::vector<int> nums; for (int i = 0; i < 10; ++i) { nums.push_back(i); // 动态扩容 } for (int n : nums) { std::cout << n << " "; } return 0; }

2.3. std :: array使用场景

适用于元素数量固定、性能要求高、无需动态扩容的场景:

  • 编译期已知数组大小
  • 算法中需要更快的访问速度
  • 嵌入式或高性能场景下使用
#include <iostream> #include <array> int main() { std::array<int, 5> nums = {1, 2, 3, 4, 5}; for (int n : nums) { std::cout << n << " "; } return 0; }

2.4. 对比传统数组的优势

  • 支持STL算法、迭代器
  • 类型安全、避免退化成指针

3. 描述一下vector是如何保证数组连续存储的吗?

vector内部使用动态数组作为底层存储结构,内部使用了一个单一的内存块来存储所有的元素,并且管理这个内存块的大小和容量。当vector的内存容量不够时,会重新分配一块更大的内存,并把旧数组中的数据复制到新内存块中。


4. 当vector的空间不足以容纳更多的元素时,它是如何扩容的?

vector在空间不足时,会进行扩容。vector内部实现过了一个内存分配函数,内存不够时会申请一块原内存1.5~2倍大小的新内存块,再把旧的数组复制到新的内存当中。

vector扩容时,对于使用移动语义复制对象还是直接拷贝对象,取决于对象是否支持移动语义,实现了移动构造函数


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

简要回答

两者都用于在末尾添加元素,但是两者添加的元素的方式不同:

  • push_back:创建一个元素的副本或移动该元素,然后将其添加到末尾
  • emplace_back:在向量的末尾就地构造元素。避免了额外的复制或者移动

详细回答

  • push_back:
  1. push_back方法接收一个参数,该参数可以是一个值、一个已经存在的对象的引用、或者要添加进向量末尾的元素的右值
  2. 如果这个参数是一个右值,push_back将使用移动构造函数(如果可用的话)来移动它;如果参数是一个左值,它将使用拷贝构造函数来复制
  • emplace_back:
  1. emplace_back不接受任何直接的参数,但是接收构造新元素所需要的参数,并使用这些参数在向量的末尾就地构造一个新的元素
  2. emplace_back避免了临时对象的创建与销毁,因为它直接在向量的内存上构造新对象

知识扩展:

性能:

  1. emplace_back通常比push_back更加高效,因为它省去了临时对象的创建和销毁的开销,特别是构造和析构成本较高时
  2. 当需要传递多个参数来构造向量末尾的元素时,emplace_back时,emplace_back是一个很好的选择,因为它允许你直接传递这些参数该构造函数
  3. 完美转发:emplace_back能够完美转发参数,这意味着参数的值类别(左值、右值)会被保留,这对于需要区分左值和右值的构造函数特别有用

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询