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

【C++】 Vector容器操作全解析

C++ Vector 容器详解

1. 容量与大小管理

1.1 基本容量操作

  • size():返回当前元素个数

  • capacity():返回当前分配的内存容量(可容纳的元素数)

  • empty():判断容器是否为空

1.2 容量调整操作

  • resize(n):改变 size

    • 若 n > size,新增元素默认初始化(对于基本类型为0,类类型调用默认构造函数)

    • 若 n < size,删除尾部多余元素

    • 可选第二参数指定初始化值:resize(n, value)

  • reserve(n):改变 capacity

    • 只开空间,不初始化,不影响 size

    • 如果 n < capacity,通常无效果(实现可能忽略)

    • 如果 n > capacity,重新分配内存,可能导致迭代器失效

2. Vector 的扩容机制

2.1 不同编译器的增长策略

  • VS (PJ STL):1.5 倍增长

  • g++ (SGI STL):2 倍增长

  • Clang (通常):2 倍增长

2.2 扩容性能分析

  • 摊销常数时间:虽然单次扩容可能耗时,但多次操作的均摊时间复杂度为 O(1)

  • 扩容代价:需要分配新内存、拷贝元素、释放旧内存

  • reserve 只负责开辟空间,如果确定知道需要用多少空间,reserve 可以缓解 vector 增容的代价缺陷问题。

  • resize 在开空间的同时还会进行初始化,影响 size。

// 测试vector的默认扩容机制 
void TestVectorExpand() 
{ size_t sz;  vector<int> v;  sz = v.capacity();  cout << "making v grow:\n";  for (int i = 0; i < 100; ++i)  {  v.push_back(i);  if (sz != v.capacity())  {  sz = v.capacity();  cout << "capacity changed: " << sz << '\n'; } } 
}

// 如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够 
// 就可以避免边插入边扩容导致效率低下的问题了 
void TestVectorExpandOP() 
{  vector<int> v;  size_t sz = v.capacity();  v.reserve(100); // 提前将容量设置好,可以避免一遍插入一遍扩容  cout << "making bar grow:\n";  for (int i = 0; i < 100; ++i)  {  v.push_back(i);  if (sz != v.capacity()) {  sz = v.capacity();  cout << "capacity changed: " << sz << '\n'; } } 
}

1.2.4vector 增删查改

push_back(val):尾部插入(拷贝或移动)

pop_back():尾部删除(不返回被删除元素)

emplace_back(args...)(C++11):直接在尾部构造元素,避免拷贝

emplace(pos, args...)(C++11):在指定位置直接构造元素

find 查找(注意这个是算法模块实现,不是 vector 的成员接口)

insert 在 position 之前插入 val

erase 删除 position 位置的数据

swap 交换两个 vector 的数据空间

operator[] (重点) 像数组一样访问

4.2 插入操作详解

vector<int> v = {1, 3, 4};// 插入单个元素
v.insert(v.begin() + 1, 2); // v = {1, 2, 3, 4}// 插入多个相同元素
v.insert(v.end(), 3, 5); // v = {1, 2, 3, 4, 5, 5, 5}// 插入范围
vector<int> other = {6, 7, 8};
v.insert(v.end(), other.begin(), other.end()); // v = {1, 2, 3, 4, 5, 5, 5, 6, 7, 8}// 使用初始化列表插入(C++11)
v.insert(v.begin(), {0, -1}); // v = {-1, 0, 1, 2, 3, 4, 5, 5, 5, 6, 7, 8}

4.3 删除操作详解

vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};// 删除单个元素
v.erase(v.begin()); // 删除第一个元素// 删除范围
v.erase(v.begin() + 2, v.begin() + 4); // 删除第3和第4个元素// 删除所有元素
v.clear();// 删除满足条件的元素(使用erase-remove惯用法)
vector<int> v2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
v2.erase(remove_if(v2.begin(), v2.end(), [](int x) { return x % 2 == 0; }), v2.end());
// 删除所有偶数

4.4 查找操作扩展

#include <algorithm>
#include <vector>vector<int> v = {1, 2, 3, 4, 5, 3, 2, 1};// 查找第一个匹配元素
auto it = find(v.begin(), v.end(), 3);
if (it != v.end()) {cout << "Found at position: " << distance(v.begin(), it) << endl;
}// 查找最后一个匹配元素
auto rit = find(v.rbegin(), v.rend(), 3);
if (rit != v.rend()) {cout << "Last found at position: " << distance(v.begin(), rit.base()) - 1 << endl;
}// 查找第一个满足条件的元素
auto it2 = find_if(v.begin(), v.end(), [](int x) { return x > 3; });// 查找子序列
vector<int> sub = {3, 4};
auto it3 = search(v.begin(), v.end(), sub.begin(), sub.end());

Lambda 表达式

[capture](parameters) -> return_type { function_body }

具体分解

  • []: 捕获列表(空,表示不捕获任何外部变量)

  • (int x): 参数列表(接受一个整数参数 x)

  • { return x > 3; }: 函数体(返回 x > 3 的比较结果)

Lambda 表达式的特性

  1. 匿名函数:没有函数名,直接定义和使用

  2. 类型推导:编译器自动推导返回类型(这里返回 bool

  3. 捕获能力:可以通过捕获列表访问外部变量(这里没有使用)

等价函数

这个 lambda 表达式等价于以下传统函数:

bool greater_than_three(int x) {return x > 3;
}

Lambda 表达式的更多用法

捕获外部变量

int threshold = 3;
// 通过值捕获外部变量
auto it = find_if(v.begin(), v.end(), [threshold](int x) { return x > threshold; });// 通过引用捕获外部变量
auto it = find_if(v.begin(), v.end(), [&threshold](int x) { return x > threshold; });

指定返回类型

// 显式指定返回类型
auto it = find_if(v.begin(), v.end(), [](int x) -> bool { return x > 3; });

复杂逻辑

// 多个条件的lambda
auto it = find_if(v.begin(), v.end(), [](int x) { return x > 3 && x % 2 == 0; // 大于3的偶数
});

4.5 访问操作扩展

vector<int> v = {1, 2, 3, 4, 5};// 使用operator[](不检查边界)
int a = v[2]; // a = 3// 使用at()(检查边界)
try {int b = v.at(10); // 抛出std::out_of_range异常
} catch (const out_of_range& e) {cout << "Out of range: " << e.what() << endl;
}// 访问首尾元素
int first = v.front(); // 等同于v[0]
int last = v.back();   // 等同于v[v.size()-1]// 直接访问底层数据
int* data = v.data(); // 获取指向底层数组的指针

标准库算法 std::find 的返回值是迭代器:

C++ 标准库的算法(如 findsort 等)是通用的,可以适配各种容器(vectorlistset 等)。

  • 迭代器为不同容器提供了统一的访问接口:无论容器内部存储结构如何(数组、链表等),算法都能通过迭代器遍历和操作元素。

  • 若不使用迭代器,find 函数需要为每种容器单独实现(如 vector 用索引,list 用指针等),违背了代码复用的原则。

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

相关文章:

  • springboot:数据校验
  • 人工智能之数学基础:常用的连续型随机变量的分布
  • Web知识的总结
  • 直播预告 | Excelize 跨语言实战
  • 搭载AX650N高能效比智能视觉芯片——AX2050系列边缘计算盒,可应用在智慧安防交通仓储教育,人脸识别,明厨亮灶,安全生产,智能机器人等
  • Linux ARP老化机制/探测机制/ip neigh使用
  • 前端性能优化实战:如何高效管理和加载图片、字体、脚本资源
  • 数组(4)
  • 重构导航之核:高德地图的深度学习架构解析 导论:从数字化世界到可计算世界
  • TensorFlow深度学习实战(36)——自动机器学习(AutoML)
  • 从能耗黑洞到精准智控:ASCB2智慧空开重构高校宿舍用电能效模型
  • 英伟达Newton与OpenTwins如何重构具身智能“伴随式数采”范式
  • PHP 日志最佳实践
  • 【项目】多模态RAG必备神器—olmOCR重塑PDF文本提取格局
  • 江协科技STM32学习笔记补充之001。为什么C语言在对STM32编程过程中的二进制要用十六进制来进行读写。而不能直接用二进制来进行读写。
  • [Linux]学习笔记系列 -- mm/slub.c SLUB内存分配器(The SLUB Allocator) 现代内核对象缓存的核心
  • 【开题答辩全过程】以 基于php的校园兼职求职网站为例,包含答辩的问题和答案
  • 《梨树下的家》文学分析与研究
  • MVC问题记录
  • Linux初始——编译器gcc
  • [Java]PTA:jmu-java-01入门-基本输入
  • Spark自定义累加器实现高效WordCount
  • 众擎机器人开源代码解读
  • 液态神经网络(LNN)2:LTC改进成CFC详细推导过程
  • Linux 孤儿进程 (Orphan Process)
  • 动作指令活体检测通过动态交互验证真实活人,保障安全
  • 【大模型】大模型微调-RLHF(强化学习)
  • 技术速递|构建你的第一个 MCP 服务器:如何使用自定义功能扩展 AI 工具
  • 分享智能电动窗帘方案
  • 串口通讯个人见解