专门做调查问卷的网站,做美食的视频网站有哪些,新手怎么注册自媒体账号,个人免费发布招聘信息前言
本文将带你穿越C容器的迷雾森林#xff1a;从vector动态扩容的数学玄机#xff0c;到emplace_back比push_back快在哪的微观真相#xff1b;从红黑树与哈希表的世纪对决#xff0c;到连续存储背后的内存博弈。无论你是渴望通过大厂面试的技术追梦人#xff0c;还是致…前言本文将带你穿越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容器了解那些简要回答CSTL中主要有三类容器顺序容器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容器可以分为三大类序列容器维护元素的线性序列vector动态数组支持快速随机访问deque双端队列两端高效插入和删除forward_list单向链表任意位置高效插入和删除array固定大小数组更安全的原生数组替代关联容器基于键值对的有序存储set/multiset有序唯一/非唯一键集合map/multimap有序键值对集合键唯一/非唯一无序关联容器基于哈希表的存储unordered_set/unordered_multisetunordered_map/unordered_multimap每种容器在时间复杂度、内存布局和使用场景下有所不同。STL的特点如下序列容器容器特点vector动态数组随机访问快尾部插入快list双向链表任意位置插入/删除快deque双端队列头尾都能快速插入/删除array固定大小数组C11forward_list单向链表C11关联容器有序就红黑树容器特点set唯一元素自动排序multiset元素允许重复map键值对键唯一multimap键值对键可重复无序关联容器基于哈希表C11容器特点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() { vectorint vec {1, 2, 3}; vec.push_back(4); // 动态数组 listint lst {10, 20, 30}; lst.push_front(5); // 双向链表 setint s {5, 2, 3, 2}; // 自动去重排序 mapstring, int m {{Tom, 90}, {Jerry, 85}}; // 字典 unordered_mapstring, 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::arrayC11 引入大小动态可变固定不变编译时确定内存分配堆动态分配栈静态分配标准库支持C98 起就有C11 起引入元素访问支持下标访问和迭代器同样支持效率稍慢涉及动态分配更快在栈上分配无需额外开销2.2. std :: vector 使用场景适用于元素数量运行时变化、在末尾频繁插入删除、需要自动扩容的场景动态读取用户输入或文件内容使用STL算法是需要可变容器如排序实现堆栈、队列、图等动态结构#include iostream #include vector int main() { std::vectorint 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::arrayint, 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_backpush_back方法接收一个参数该参数可以是一个值、一个已经存在的对象的引用、或者要添加进向量末尾的元素的右值如果这个参数是一个右值push_back将使用移动构造函数如果可用的话来移动它如果参数是一个左值它将使用拷贝构造函数来复制emplace_backemplace_back不接受任何直接的参数但是接收构造新元素所需要的参数并使用这些参数在向量的末尾就地构造一个新的元素emplace_back避免了临时对象的创建与销毁因为它直接在向量的内存上构造新对象知识扩展性能emplace_back通常比push_back更加高效因为它省去了临时对象的创建和销毁的开销特别是构造和析构成本较高时当需要传递多个参数来构造向量末尾的元素时emplace_back时emplace_back是一个很好的选择因为它允许你直接传递这些参数该构造函数完美转发emplace_back能够完美转发参数这意味着参数的值类别左值、右值会被保留这对于需要区分左值和右值的构造函数特别有用