C++ std::vector 使用與迭代器速成密籍

std::vector 是 C++ 中一種常用的動態陣列容器,它可以自動調整大小,並提供方便的操作方法。本文將透過三個範例教學來詳細介紹 vector 的使用、迭代器的應用,以及為什麼迭代器在某些情況下比指標更適合。

函式速查表

1. 向量初始化

函式 功能 範例
vector<T> v; 建立空的向量 vector<int> v;
vector<T> v(n, val); 建立大小為 n 的向量,初始值為 val vector<int> v(5, 0);
vector<T> v{val1, val2}; 使用初始列表初始化向量 vector<int> v{1, 2, 3};
vector<T> v(v2); 複製另一個向量 vector<int> v2 = v;
vector<T> v(v2.begin(), v2.end()); 初始化為另一範圍 vector<int> v(v2.begin(), v2.begin() + 3);
vector<vector<T>> mat; 建立空的二維向量 vector<vector<int>> mat;
vector<vector<T>> mat(rows, vector<T>(cols)); 建立大小為 rows x cols 的二維向量 vector<vector<int>> mat(3, vector<int>(4));
vector<vector<T>> mat(rows, vector<T>(cols, val)); 建立並初始化所有元素為 val vector<vector<int>> mat(3, vector<int>(4, -1));

2. 基本操作

函式 功能 範例
v.push_back(val); 在向量末尾添加元素 v.push_back(10);
v.pop_back(); 刪除向量末尾的元素 v.pop_back();
v.size(); 返回向量的大小 cout << v.size();
v.capacity(); 返回向量的容量(記憶體分配空間) cout << v.capacity();
v.empty(); 判斷向量是否為空 if (v.empty()) { cout << "Empty"; }
v.clear(); 清空所有元素 v.clear();

3. 訪問元素

函式 功能 範例
v[i]; 使用索引訪問元素 cout << v[0];
v.at(i); 安全訪問第 i 個元素(會檢查邊界) cout << v.at(0);
v.front(); 返回第一個元素 cout << v.front();
v.back(); 返回最後一個元素 cout << v.back();
v.data(); 返回指向底層數據的指標 int* p = v.data(); cout << p[0];

4. 修改向量

函式 功能 範例
v.insert(pos, val); 在指定位置 pos 插入元素 val v.insert(v.begin(), 10);
v.insert(pos, n, val); pos 插入 n 個值 val v.insert(v.begin(), 3, 10);
v.erase(pos); 刪除指定位置的元素 v.erase(v.begin() + 1);
v.erase(start, end); 刪除範圍內的元素 v.erase(v.begin() + 1, v.begin() + 3);
v.resize(n); 調整向量大小為 n(多出部分為默認值) v.resize(5);
v.resize(n, val); 調整大小為 n,多出部分填充為 val v.resize(5, 0);
v.swap(v2); 與另一個向量 v2 交換內容 v.swap(v2);

5. 迭代器相關

函式 功能 範例
v.begin(); 返回指向第一個元素的迭代器 auto it = v.begin();
v.end(); 返回指向最後一個元素下一位置的迭代器 for (auto it = v.begin(); it != v.end(); ++it) { cout << *it; }
v.rbegin(); 返回指向最後一個元素的反向迭代器 for (auto it = v.rbegin(); it != v.rend(); ++it) { cout << *it; }
v.rend(); 返回指向第一個元素前一位置的反向迭代器
v.cbegin(); 返回指向第一個元素的常量迭代器 auto it = v.cbegin();
v.cend(); 返回指向最後一個元素下一位置的常量迭代器
v.crbegin(); 返回指向最後一個元素的反向常量迭代器
v.crend(); 返回指向第一個元素前一位置的反向常量迭代器

6. 容量操作

函式 功能 範例
v.reserve(n); 預留至少 n 的空間 v.reserve(100);
v.shrink_to_fit(); 將容量縮小為當前大小 v.shrink_to_fit();

1. std::vector 的基本使用

vector 的特性

  • 動態大小:可以根據需求自動調整容量。
  • 隨機存取:支持索引操作,與普通陣列類似。
  • 內建方法:提供高效的插入、刪除等功能。
  • 與 STL 演算法整合:可以與 sort 等標準函數配合使用。

範例 1:逐步刪除並反轉 vector 的元素

題目描述:

  1. 輸入一個整數 ( n ),表示有 ( n ) 個元素,然後輸入這些元素。
  2. 打印出當前的所有元素。
  3. 刪除第一個元素。
  4. 反轉剩餘的元素。
  5. 重複步驟 2-4,直到元素全部刪除。

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
int n, num;

// 讀取輸入
cin >> n;
vector<int> vec;
for (int i = 0; i < n; ++i) {
cin >> num;
vec.push_back(num);
}

// 執行刪除與反轉的操作
while (!vec.empty()) {
// 打印當前所有元素
for (const auto &x : vec) {
cout << x << " ";
}
cout << endl;

// 刪除第一個元素
vec.erase(vec.begin());

// 反轉剩餘的元素
reverse(vec.begin(), vec.end());
}

return 0;
}

執行範例

輸入:

1
2
5
1 3 5 7 9

輸出:

1
2
3
4
5
1 3 5 7 9
9 7 5 3
3 5 7
7 5
5

程式解說

  1. 使用 vector<int> 存儲輸入數字。
  2. 使用 erase(vec.begin()) 刪除第一個元素。
  3. 使用 reverse(vec.begin(), vec.end()) 反轉向量。
  4. 使用範圍式 for 迴圈打印元素。

2. 交換 vector 中的列

範例 2:交換矩陣中指定的兩列

題目描述:

  1. 輸入一個 ( n \times n ) 的矩陣。
  2. 輸入兩個整數 ( a ) 和 ( b ),交換矩陣中第 ( a ) 列和第 ( b ) 列。
  3. 打印交換後的矩陣。

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <vector>
using namespace std;

int main() {
int n, a, b;

// 讀取矩陣大小
cin >> n;

// 定義 n x n 矩陣
vector<vector<int>> matrix(n, vector<int>(n));

// 讀取矩陣內容
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> matrix[i][j];
}
}

// 讀取要交換的列
cin >> a >> b;

// 交換第 a 列和第 b 列
for (int i = 0; i < n; ++i) {
swap(matrix[i][a], matrix[i][b]);
}

// 打印交換後的矩陣
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cout << matrix[i][j] << " ";
}
cout << endl;
}

return 0;
}

執行範例

輸入:

1
2
3
4
5
3
1 2 3
4 5 6
7 8 9
0 1

輸出:

1
2
3
2 1 3
5 4 6
8 7 9

程式解說

  1. 使用 vector<vector<int>> 存儲矩陣。
  2. 使用 swap(matrix[i][a], matrix[i][b]) 交換指定的兩列。
  3. 打印矩陣時使用雙層迴圈遍歷。

3. 使用迭代器查找非重複數字

題目描述:

  1. 輸入兩組數字,找出它們中不重複的數字。
  2. 使用 vector 實現。

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
int n, m, num;

// 讀取第一組數字
cin >> n;
vector<int> vec1;
for (int i = 0; i < n; ++i) {
cin >> num;
vec1.push_back(num);
}

// 讀取第二組數字
cin >> m;
vector<int> vec2;
for (int i = 0; i < m; ++i) {
cin >> num;
vec2.push_back(num);
}

// 儲存結果
vector<int> result;

// 找出 vec1 中不在 vec2 的數字
for (auto it = vec1.begin(); it != vec1.end(); ++it) {
if (find(vec2.begin(), vec2.end(), *it) == vec2.end()) {
result.push_back(*it);
}
}

// 找出 vec2 中不在 vec1 的數字
for (auto it = vec2.begin(); it != vec2.end(); ++it) {
if (find(vec1.begin(), vec1.end(), *it) == vec1.end()) {
result.push_back(*it);
}
}

// 排序並輸出
sort(result.begin(), result.end());
for (const auto &x : result) {
cout << x << " ";
}

return 0;
}

執行範例

輸入:

1
2
3
4
3
3 4 5
4
1 3 5 7

輸出:

1
1 4 7

4. 為什麼迭代器比指標更好?

1. 統一性與可讀性

  • 迭代器
    • 針對所有 STL 容器(如 vector, list, map 等)都可以使用統一的操作方式。
    • 使用範例:
      1
      2
      3
      for (auto it = vec.begin(); it != vec.end(); ++it) {
      cout << *it << " ";
      }
  • 指標
    • 指標無法適應非連續容器(如 list)。
    • 容易引發記憶體操作錯誤。

2. 安全性

  • 迭代器具有更多邊界檢查,避免越界。
  • 指標則可能指向未分配的記憶體。

3. 與 STL 算法整合

  • 迭代器可直接用於標準演算法,如 std::sort, std::find
  • 指標僅能操作基礎陣列。

總結

  • std::vector 是 C++ 中功能強大的容器,適合動態大小數據的處理。
  • 迭代器提供了統一的操作方式,比指標更安全、靈活且易於整合。
  • 熟練使用 vector 和迭代器能大大提升程式的效率和可讀性。