C++ --vector

📅 2026/7/24 17:57:52 👁️ 阅读次数 📝 编程学习
C++ --vector

1. 核心特点

std::vector动态数组,元素在内存中连续存储,支持随机访问,能在尾部高效增删。

2. 基本操作

创建与初始化
#include <vector> using namespace std; vector<int> v1; // 空 vector<int> v2(10); // 10个元素,值初始化为0 vector<int> v3(10, 5); // 10个5 vector<int> v4 = {1,2,3,4}; // 列表初始化 vector<int> v5(v4); // 拷贝构造

常用成员函数

一、构造与赋值
1. 默认构造vector()

创建一个空的 vector,没有任何元素。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v; // 默认构造,空容器 cout << "size = " << v.size() << endl; // 输出: 0 cout << "empty = " << v.empty() << endl; // 输出: 1 (true) return 0; }
2. 指定大小构造vector(n)vector(n, val)

vector(n)创建 n 个元素,值初始化为 0(对 int 来说)。
vector(n, val)创建 n 个元素,都初始化为 val。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v1(5); // 5个元素,默认初始化为0 vector<int> v2(5, 10); // 5个元素,都初始化为10 cout << "v1: "; for (int x : v1) cout << x << " "; // 输出: 0 0 0 0 0 cout << endl; cout << "v2: "; for (int x : v2) cout << x << " "; // 输出: 10 10 10 10 10 cout << endl; return 0; }
3. 列表初始化vector(initializer_list)

用花括号直接初始化,最直观的方式。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {1, 2, 3, 4, 5}; // 列表初始化 // 或者 vector<int> v{1, 2, 3, 4, 5}; cout << "元素: "; for (int x : v) cout << x << " "; // 输出: 1 2 3 4 5 cout << endl; cout << "size = " << v.size() << endl; // 输出: 5 return 0; }
4. 拷贝构造vector(const vector&)
#include <iostream> #include <vector> using namespace std; int main() { vector<int> v1 = {1, 2, 3, 4, 5}; // 拷贝构造 vector<int> v2(v1); // 深拷贝,v1 和 v2 独立 v2.push_back(6); cout << "v1: "; for (int x : v1) cout << x << " "; // 输出: 1 2 3 4 5 cout << endl; cout << "v2: "; for (int x : v2) cout << x << " "; // 输出: 1 2 3 4 5 6 cout << endl; return 0; }
5. 赋值operator=assign()

operator=:赋值,清空原内容并拷贝新内容。
assign():重新赋值,可以指定数量和值,或迭代器区间。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v1 = {1, 2, 3}; vector<int> v2 = {4, 5, 6, 7}; // operator= v1 = v2; // v1 变成 {4, 5, 6, 7} cout << "v1 = v2 后: "; for (int x : v1) cout << x << " "; // 输出: 4 5 6 7 cout << endl; // assign:清空并重新赋值 v1.assign(3, 100); // 3个100 cout << "v1.assign(3, 100) 后: "; for (int x : v1) cout << x << " "; // 输出: 100 100 100 cout << endl; // assign 用迭代器区间 v2.assign(v1.begin(), v1.end()); // v2 变成 {100, 100, 100} cout << "v2 变成: "; for (int x : v2) cout << x << " "; cout << endl; return 0; }

二、容量相关

6.size()capacity()

size():当前元素个数。
capacity():当前已分配内存能容纳的元素个数(总是 >= size)。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v; cout << "初始: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 输出: 初始: size=0, capacity=0 v.push_back(1); cout << "push 1 后: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 可能输出: push 1 后: size=1, capacity=1 v.push_back(2); v.push_back(3); cout << "push 3 个后: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 可能输出: push 3 个后: size=3, capacity=4 (容量可能翻倍) return 0; }
7.empty()

判断容器是否为空,比size() == 0更高效(O(1))。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v; if (v.empty()) { cout << "v 是空的" << endl; // 输出这行 } v.push_back(42); if (!v.empty()) { cout << "v 现在有 " << v.size() << " 个元素" << endl; // 输出: v 现在有 1 个元素 } return 0; }
8.reserve(n)

预分配至少 n 个元素的空间,只改变 capacity,不改变 size。
用途:提前知道元素数量时,避免多次扩容。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v; v.reserve(100); // 提前分配 100 个元素的空间 cout << "reserve(100) 后: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 输出: reserve(100) 后: size=0, capacity=100 for (int i = 0; i < 100; ++i) { v.push_back(i); // 这 100 次 push 不会触发扩容 } cout << "插入 100 个元素后: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 输出: 插入 100 个元素后: size=100, capacity=100 return 0; }
9.resize(n)resize(n, val)

改变 size 为 n:

  • 如果 n > 当前 size:尾部新增元素,用默认值或 val 填充

  • 如果 n < 当前 size:尾部删除元素

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {1, 2, 3, 4, 5}; cout << "初始: "; for (int x : v) cout << x << " "; // 输出: 1 2 3 4 5 cout << ", size=" << v.size() << endl; // resize 变大,用默认值填充 v.resize(8); cout << "resize(8) 后: "; for (int x : v) cout << x << " "; // 输出: 1 2 3 4 5 0 0 0 cout << ", size=" << v.size() << endl; // resize 变大,用指定值填充 v.resize(10, 99); cout << "resize(10, 99) 后: "; for (int x : v) cout << x << " "; // 输出: 1 2 3 4 5 0 0 0 99 99 cout << ", size=" << v.size() << endl; // resize 变小,删除尾部元素 v.resize(3); cout << "resize(3) 后: "; for (int x : v) cout << x << " "; // 输出: 1 2 3 cout << ", size=" << v.size() << endl; return 0; }
10.shrink_to_fit()

请求将 capacity 缩小到刚好等于 size(释放多余内存)。这是非强制请求,实现可能忽略。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v; v.reserve(1000); for (int i = 0; i < 10; ++i) v.push_back(i); cout << "添加 10 个元素后: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 输出: 添加 10 个元素后: size=10, capacity=1000 v.shrink_to_fit(); // 请求缩容 cout << "shrink_to_fit 后: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 输出: shrink_to_fit 后: size=10, capacity=10 (可能) return 0; }

三、元素访问

11.operator[](idx)at(idx)

两者都通过下标访问元素。

  • operator[]:无边界检查,性能更高,越界是未定义行为。

  • at():有边界检查,越界抛出std::out_of_range异常。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {10, 20, 30, 40, 50}; // operator[] - 无检查 cout << "v[0] = " << v[0] << endl; // 输出: 10 cout << "v[2] = " << v[2] << endl; // 输出: 30 v[1] = 99; // 修改 cout << "修改后 v[1] = " << v[1] << endl; // 输出: 99 // at() - 有检查 try { cout << "v.at(0) = " << v.at(0) << endl; // 输出: 10 cout << "v.at(10) = " << v.at(10) << endl; // 越界,抛异常 } // 危险:operator[] 越界不会报错(未定义行为) // cout << v[100] << endl; // 不能这样写 return 0; }
12.front()back()

访问第一个和最后一个元素的引用。空容器调用是未定义行为。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {1, 2, 3, 4, 5}; cout << "第一个元素: " << v.front() << endl; // 输出: 1 cout << "最后一个元素: " << v.back() << endl; // 输出: 5 // 可以修改 v.front() = 100; v.back() = 200; cout << "修改后: "; for (int x : v) cout << x << " "; // 输出: 100 2 3 4 200 cout << endl; // 注意:空容器调用 front/back 是未定义行为 vector<int> empty; // cout << empty.front() << endl; // 不要这样写 return 0; }
13.data()

返回指向底层数组的指针。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {1, 2, 3, 4, 5}; int* p = v.data(); // 获取底层数组指针 cout << "通过指针访问: "; for (size_t i = 0; i < v.size(); ++i) { cout << p[i] << " "; // 输出: 1 2 3 4 5 } cout << endl; // 修改也能反映到 vector p[0] = 99; cout << "修改后 v[0] = " << v[0] << endl; // 输出: 99 return 0; }

四、增删操作

14.push_back(val)pop_back()

尾部插入和尾部删除,都是高效操作(均摊 O(1))。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v; // push_back 尾部插入 v.push_back(10); v.push_back(20); v.push_back(30); cout << "push 3 个后: "; for (int x : v) cout << x << " "; // 输出: 10 20 30 cout << ", size=" << v.size() << endl; // pop_back 尾部删除 v.pop_back(); // 删除 30 cout << "pop 一个后: "; for (int x : v) cout << x << " "; // 输出: 10 20 cout << ", size=" << v.size() << endl; // pop_back 不返回元素,想获取尾部元素用 back() if (!v.empty()) { int last = v.back(); v.pop_back(); cout << "删除了最后一个元素: " << last << endl; // 输出: 20 } return 0; }
15.emplace_back( )

尾部就地构造元素,避免临时对象产生,比 push_back 更高效。

#include <iostream> #include <vector> #include <string> using namespace std; struct Person { string name; int age; Person(string n, int a) : name(n), age(a) { cout << "构造: " << name << endl; } }; int main() { vector<Person> v; cout << "使用 push_back:" << endl; v.push_back(Person("张三", 25)); // 先构造临时对象,再拷贝到 vector cout << endl; cout << "使用 emplace_back:" << endl; v.emplace_back("李四", 30); // 直接在 vector 内部构造,无临时对象 cout << endl; // 对于基本类型,emplace_back 和 push_back 差不多 vector<int> vi; vi.emplace_back(42); // 相当于 push_back(42) return 0; }
16.insert(pos, val)insert(pos, n, val)

在指定位置插入元素(单个或多个),会移动后续元素,时间复杂度 O(n)。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {1, 2, 4, 5}; cout << "初始: "; for (int x : v) cout << x << " "; // 输出: 1 2 4 5 cout << endl; // 在 begin()+2 位置插入 3 auto it = v.insert(v.begin() + 2, 3); cout << "插入 3 后: "; for (int x : v) cout << x << " "; // 输出: 1 2 3 4 5 cout << ", 插入位置指向: " << *it << endl; // 返回指向新元素的迭代器 // 在 begin()+1 位置插入 3 个 99 v.insert(v.begin() + 1, 3, 99); cout << "插入 3 个 99 后: "; for (int x : v) cout << x << " "; // 输出: 1 99 99 99 2 3 4 5 cout << endl; return 0; }

17.emplace(pos, args...)

在指定位置就地构造元素,比 insert 更高效。

#include <iostream> #include <vector> #include <string> using namespace std; struct Person { string name; int age; Person(string n, int a) : name(n), age(a) {} }; int main() { vector<Person> v; v.emplace_back("张三", 25); v.emplace_back("王五", 35); // 在 begin()+1 位置就地构造 auto it = v.emplace(v.begin() + 1, "李四", 30); cout << "插入后: " << endl; for (const auto& p : v) { cout << p.name << " (" << p.age << "岁)" << endl; } // 输出: // 张三 (25岁) // 李四 (30岁) // 王五 (35岁) return 0; }
18.erase(pos)erase(first, last)

删除单个元素或区间元素,会移动后续元素,时间复杂度 O(n)。返回指向被删元素之后元素的迭代器。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {10, 20, 30, 40, 50, 60, 70}; cout << "初始: "; for (int x : v) cout << x << " "; // 输出: 10 20 30 40 50 60 70 cout << endl; // 删除单个元素(位置 3,即 40) auto it = v.erase(v.begin() + 3); cout << "删除 40 后: "; for (int x : v) cout << x << " "; // 输出: 10 20 30 50 60 70 cout << ", 返回的迭代器指向: " << *it << endl; // 输出: 50 // 删除区间 [begin()+1, begin()+3),即删除 20, 30 it = v.erase(v.begin() + 1, v.begin() + 3); cout << "删除 20,30 后: "; for (int x : v) cout << x << " "; // 输出: 10 50 60 70 cout << ", 返回的迭代器指向: " << *it << endl; // 输出: 50 // 常见用法:删除所有偶数 vector<int> v2 = {1, 2, 3, 4, 5, 6, 7, 8}; for (auto it2 = v2.begin(); it2 != v2.end(); ) { if (*it2 % 2 == 0) { it2 = v2.erase(it2); // erase 返回下一个有效迭代器 } else { ++it2; } } cout << "删除偶数后: "; for (int x : v2) cout << x << " "; // 输出: 1 3 5 7 cout << endl; return 0; }
19.clear()

删除所有元素,size 变为 0,但 capacity 通常不变(内存不释放)。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {1, 2, 3, 4, 5}; cout << "清空前: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 输出: 清空前: size=5, capacity=5 v.clear(); cout << "清空后: size=" << v.size() << ", capacity=" << v.capacity() << endl; // 输出: 清空后: size=0, capacity=5 (capacity 不变) cout << "是否为空: " << (v.empty() ? "是" : "否") << endl; // 输出: 是 // 如果也想释放内存,用 shrink_to_fit 或 swap vector<int>().swap(v); // 彻底释放内存 return 0; }
20.swap(v2)

交换两个 vector 的内容,O(1) 时间,只交换内部指针。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v1 = {1, 2, 3, 4, 5}; vector<int> v2 = {10, 20, 30}; cout << "交换前:" << endl; cout << "v1: "; for (int x : v1) cout << x << " "; // 输出: 1 2 3 4 5 cout << endl; cout << "v2: "; for (int x : v2) cout << x << " "; // 输出: 10 20 30 cout << endl; v1.swap(v2); // 交换内容 cout << "交换后:" << endl; cout << "v1: "; for (int x : v1) cout << x << " "; // 输出: 10 20 30 cout << endl; cout << "v2: "; for (int x : v2) cout << x << " "; // 输出: 1 2 3 4 5 cout << endl; // 释放内存 vector<int> v3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cout << "v3 清空前: size=" << v3.size() << ", capacity=" << v3.capacity() << endl; vector<int>().swap(v3); // 清空并释放内存 cout << "v3 清空后: size=" << v3.size() << ", capacity=" << v3.capacity() << endl; return 0; }

五、迭代器 迭代器的基本知识

21.begin()/end()cbegin()/cend()

获取迭代器,用于遍历。begin()返回普通迭代器,cbegin()返回 const 迭代器。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {10, 20, 30, 40, 50}; // 正向遍历 cout << "正向遍历: "; for (auto it = v.begin(); it != v.end(); ++it) { cout << *it << " "; // 输出: 10 20 30 40 50 } cout << endl; // 使用 const 迭代器(不能修改) cout << "const 迭代器: "; for (auto it = v.cbegin(); it != v.cend(); ++it) { cout << *it << " "; // 输出: 10 20 30 40 50 // *it = 100; // 错误:不能通过 const 迭代器修改 } cout << endl; // 范围 for 本质上也是用 begin/end cout << "范围 for: "; for (int x : v) cout << x << " "; cout << endl; return 0; }

六、比较运算符

22.==, !=, <, <=, >, >=

按字典序比较两个 vector 的元素。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v1 = {1, 2, 3, 4, 5}; vector<int> v2 = {1, 2, 3, 4, 5}; vector<int> v3 = {1, 2, 3, 4, 6}; vector<int> v4 = {1, 2, 3}; cout << "v1 == v2: " << (v1 == v2) << endl; // 输出: 1 (true) cout << "v1 == v3: " << (v1 == v3) << endl; // 输出: 0 (false) cout << "v1 < v3: " << (v1 < v3) << endl; // 输出: 1 (true, 5<6) cout << "v1 < v4: " << (v1 < v4) << endl; // 输出: 0 (false, 前3个相等但v1更长) cout << "v4 < v1: " << (v4 < v1) << endl; // 输出: 1 (true, v4是v1的前缀) return 0; }

动态二维数组的理解

一、什么是动态二维数组?

静态二维数组:在编译时就要确定大小,比如int arr[3][4]

动态二维数组:在运行时才确定行数和列数,可以根据需要动态调整。

#include <iostream> using namespace std; int main() { int rows, cols; cout << "请输入行数和列数: "; cin >> rows >> cols; // 静态数组做不到(编译时就要知道大小) // int arr[rows][cols]; // 错误! // 动态二维数组可以在运行时确定大小 // 需要动态分配内存... return 0; }

二、为什么需要动态二维数组?

场景1:数据量不确定
// 读取用户输入的数据,不知道有多少行 vector<vector<int>> data; int value; while (cin >> value) { data.push_back({value}); // 动态增加行 }

场景2:每行长度不同

// 三角形矩阵:第 i 行有 i+1 个元素 int n = 5; vector<vector<int>> triangle(n); for (int i = 0; i < n; ++i) { triangle[i].resize(i + 1); // 每行长度不同 }

场景3:程序运行时才知道大小

// 图像处理:读入图片才知道尺寸 int width, height; readImageSize(width, height); int** p = new int*[height]; for (int i = 0; i < height; ++i) { p[i] = new int[width]; }

三、使用vector<vector<T>>实现动态二维数组

原理:外层 vector 的每个元素是一个 vector,每个内层 vector 独立管理自己的内存。

#include <iostream> #include <vector> using namespace std; int main() { int rows = 3, cols = 4; // 创建 3x4 的二维数组,所有元素初始化为 0 vector<vector<int>> matrix(rows, vector<int>(cols, 0)); // 赋值 for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { matrix[i][j] = i * cols + j; } } // 遍历 cout << "矩阵内容:" << endl; for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { cout << matrix[i][j] << "\t"; } cout << endl; } // 输出: // 0 1 2 3 // 4 5 6 7 // 8 9 10 11 // 每行可以有不同的长度 vector<vector<int>> jagged(3); jagged[0] = {1, 2, 3}; jagged[1] = {4, 5}; jagged[2] = {6, 7, 8, 9}; cout << "\n" << endl; for (int i = 0; i < jagged.size(); ++i) { cout << "第" << i << "行有" << jagged[i].size() << "个元素: "; for (int x : jagged[i]) cout << x << " "; cout << endl; } return 0; }

内存布局

matrix (vector对象) └── [vector<int>] ──→ [0][1][2][3] (连续内存) └── [vector<int>] ──→ [4][5][6][7] (连续内存) └── [vector<int>] ──→ [8][9][10][11] (连续内存) ↑ 每行内存独立,不一定连续