【C++ 筆記】vector - part 16

很感謝你點進來這篇文章。

你好,我並不是什麼 C++、程式語言的專家,所以本文若有些錯誤麻煩請各位鞭大力一點,我極需各位的指正及指導!!本系列文章的性質主要以詼諧的口吻,一派輕鬆的態度自學程式語言,如果你喜歡,麻煩留言說聲文章讚讚吧!

簡介(Introduction)

在 C++ 中,vector 就像可調整大小的陣列 array。

vector 和 array 都是用於儲存相同資料型態的多元素資料結構(Data structure)。

兩者之間最大的差別,就是:

:::success
vector:可調整大小。
array:不可調整大小,初始化時就固定了。
:::

其中 vector 最重要的就是能夠自動管理記憶體使用,不必我們手動分配、釋放記憶體。

根據菜鳥教程,將 vector 列出了以下四點基本特性:

  1. 動態大小:vector 的大小可以根據需要而自動增長和縮小。
  2. 連續存儲:vector 中的元素在記憶體中是連續儲存的,這使得存取元素非常快速。
  3. 可迭代:vector 可以被迭代,所以可用迴圈(如 for 迴圈)來存取它的元素。
  4. 元素型態:vector 可以儲存任何型態的元素,包括內建類型、物件、指標等。

來源:https://www.runoob.com/cplusplus/cpp-vector.html

vector 標頭檔(vector’s header file)

要使用 vector,需要做以下的引入:

1
#include <vector>

vector 的基本運算

建立 vector(Create a vector)

1
std::vector<int> my_vector; // 表建立一個儲存整數的空 vector

or

1
2
std::vector<int> my_vector(5); // 表建立可容納五個整數的 vector, 每個元素值預設是 0
std::vector<int> my_vector(5, 10); // 同上,但表示每個元素值都是 10

or

1
std::vector<int> my_vector = {1,2,3,4,5}; // 初始化包含元素的 vector

新增元素(Add elements)

使用 (vector容器名稱).push_back(欲增加的元素) 新增,如下:

1
my_vector.push_back(1); // 新增整數 1 至 my_vector 當中

存取元素(Access a vector)

可用註標運算子 [](vector容器名稱).at(欲存取元素索引) 存取,如下:

1
2
int x = myVector[0]; // 獲取第一個元素
int y = myVector.at(1); // 獲取第二個元素

至於兩者區別,筆者引用以下文章做解釋:https://shengyu7697.github.io/std-vector/

[] operator 在回傳元素時是不會作任何的邊界檢查,而在 at() 取得元素時會作邊界的處理,如果你存取越界時 std::vector 會拋出一個 out_of_range 例外,所以 at() 提供了較為安全的存取方式。


修改元素(Change vector elements)

若要變更特定元素的值,如同陣列一般:

1
2
3
4
5
6
7
8
vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"};

// 改變第一個元素的值
// Change the value of the first element
cars[0] = "Opel";

// 現在輸出由 Opel 改成 Volvo
cout << cars[0]; // Now outputs Opel instead of Volvo

Source:https://www.w3schools.com/cpp/cpp_vectors.asp


迭代存取(Iterative access)

1
2
3
for (int element : myVector) {
std::cout << element << " ";
}

以上這種使用 for ( for-range-declaration : expression ) 的寫法稱為「以範圍為基礎的 for 語句」(Range-based for Statement)。

:::success
此種 for 語句又可稱為 for-each loop。(要注意 C++ 11 才有支援)
:::

for-range-declaration:範圍宣告。於上例中,element 變數會在每次迭代(意即每次的 for 迴圈)當中,從 myVector 當中存取一個整數,並且指定(=)給 element。

expression:範圍之運算式,表示要迭代的容器,如:vector。


刪除元素(Delete elements)

使用 erase() 方法刪除,如下:

1
myVector.erase(myVector.begin() + 2); // 刪除第三個元素

為何寫 vector.begin() + 2 而不是直接寫 2 呢?

在 C++ 中,vector.begin() 是一個內建方法(built-in method),用於取得指向 vector 開頭的迭代器(iterator)。此迭代器用於遍歷(traverse)vector 或從 vector 的開頭開始執行操作。

簡單來說,vector 提供了迭代器來存取元素,begin() 方法回傳一個指向 vector 第一個元素的迭代器,相反地,end() 方法就是回傳一個指向最後一個元素之後位置的迭代器。

迭代器本身是一種資料型態,其意義是記憶體空間的位址,若要取得其值,則使用提取運算子(Dereference):*(v.begin())

那至於「為何寫 vector.begin() + 2 而不是直接寫 2 呢?」這個問題,其實就是利用begin() 回傳的迭代器進行偏移,可以取得指向特定元素的迭代器。

由於我們沒有要取值,只是要用 erase() 方法消除,所以直接寫 myVector.begin() + 2 即可。

有關迭代器的概念,由於解釋會較為複雜,所以留在後續章節~


清空 vector(Clear all elements)

使用 clear() 方法清除 Vector 中所有元素:

1
myVector.clear(); // 清空 vector

vector 方法整理

序號方法敘述
1vector.push_back( <type> value )將元素(element)加入 vector 的末尾
2vector.at(size_t position)回傳 vector 中的索引元素
3vector.erase(iterator position) or vector.erase(iterator start, iterator end)從 vector 中刪除多個元素
4vector.size()回傳 vector 中的元素數量(即回傳 vector 長度)
5vector.pop_back()刪除 vector 的最後一個元素
6vector.empty()檢查 vector 是否為空

註:3 中 erase 方法具有兩種形式,一種為迭代器所在位置,另一種為迭代器的起始點至結束(範圍刪除)。

更多資訊可至:https://www.w3schools.com/cpp/cpp_ref_vector.asp

vector 範例

  1. 從建立、新增、移除元素至輸出等完整 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
#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main() {
// 建立 vector
vector<string> names; // 建立一個儲存字串的 vector

// 新增元素
names.push_back("Alice"); // 增加元素 "Alice"
names.push_back("Bob"); // 增加元素 "Bob"
names.push_back("Charlie"); // 增加元素 "Charlie"

// 輸出目前 vector 的大小
cout << "目前 vector 的大小: " << names.size() << endl; // 輸出 3

// 存取元素
cout << "第一個元素: " << names.at(0) << endl; // at() 存取第一個元素
cout << "第二個元素: " << names[1] << endl; // 索引存取第二個元素

// 輸出所有元素
cout << "所有名稱: ";
for (const auto& name : names) {
cout << name << " "; // 使用範圍 for 迴圈輸出每個名稱
}
cout << endl;

// 移除最後一個元素
names.pop_back(); // 移除最後一個元素 ("Charlie")

// 輸出移除後的大小
cout << "移除後的 vector 大小: " << names.size() << endl; // 輸出 2

return 0;
}

輸出結果:

1
2
3
4
5
目前 vector 的大小: 3
第一個元素: Alice
第二個元素: Bob
所有名稱: Alice Bob Charlie
移除後的 vector 大小: 2
  1. 建立 Vector(基礎):https://www.w3schools.com/cpp/cpp_vectors.asp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <vector>

using namespace std;

int main(){
// 建立一個 vector 叫做 cars, 會以字串形式儲存
// Create a vector called cars that will store strings
vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"};

// 印出 vector 元素
// Print vector elements
for (string car : cars) {
cout << car << "\n";
}
}

輸出結果:

1
2
3
4
Volvo
BMW
Ford
Mazda
  1. [](註標運算子) 存取 Vector 元素:https://www.w3schools.com/cpp/cpp_vectors.asp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <vector>

using namespace std;

int main(){
// 建立一個 vector 叫做 cars, 會以字串形式儲存
// Create a vector called cars that will store strings
vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"};

// 取得第一個元素
// Get the first element
cout << cars[0] << endl; // Outputs Volvo : 輸出 Volvo

// 取得第二個元素
// Get the second element
cout << cars[1]; // Outputs BMW : 輸出 BMW
}

輸出結果:

1
2
Volvo
BMW
  1. 顯示 0 ~ 9 的數字:https://openhome.cc/Gossip/CppGossip/vector1.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <vector>
using namespace std;

int main() {
vector<int> number;

for(int i = 0; i < 10; i++) {
number.push_back(i);
}

while(!number.empty()) {
int n = number.back();
number.pop_back();
cout << n << endl;
}

return 0;
}

輸出結果:

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

總結

  1. 基本介紹
    • vector 是一種可調整大小的動態陣列,與靜態陣列 array 不同。
    • 特性
      • 動態大小:根據需求而調整容量。
      • 連續儲存:元素在記憶體中是連續排列,方便快速存取。
      • 可迭代:支援用迭代器及範圍 for 迴圈存取。
      • 多種型態支援:能存放基本型態、物件與指標等多種型態。
  2. 使用方式
    • #include <vector> -> 使用前請先引入函式庫
    • 建立 vector
      1
      2
      3
      4
      std::vector<int> my_vector;             // 空 vector
      std::vector<int> my_vector(5); // 含 5 元素,初值 0
      std::vector<int> my_vector(5, 10); // 含 5 元素,初值 10
      std::vector<int> my_vector = {1, 2, 3}; // 初始化指定值
    • 新增元素push_back(value) 新增元素至尾部。
    • 存取元素
      • []:快速存取,無邊界檢查。
      • at():安全存取,越界會拋出例外。
    • 修改元素:同陣列修改方式,使用索引及註標運算子 []
    • 迭代存取
      1
      2
      3
      for (int element : my_vector) {
      std::cout << element << " ";
      }
    • 刪除元素
      • 單一位置:erase(iterator)
      • 範圍刪除:erase(iterator_start, iterator_end)
    • 清空 vector
      • clear()
  3. 常用方法表
序號方法敘述
1vector.push_back( <type> value )將元素(element)加入 vector 的末尾
2vector.at(size_t position)回傳 vector 中的索引元素
3vector.erase(iterator position) or vector.erase(iterator start, iterator end)從 vector 中刪除多個元素
4vector.size()回傳 vector 中的元素數量(即回傳 vector 長度)
5vector.pop_back()刪除 vector 的最後一個元素
6vector.empty()檢查 vector 是否為空

註:3 中 erase 方法具有兩種形式,一種為迭代器所在位置,另一種為迭代器的起始點至結束(範圍刪除)。

更多資訊可至:https://www.w3schools.com/cpp/cpp_ref_vector.asp

  1. 優點及注意事項
    • 優點:
      • 自動管理記憶體,免手動設定與釋放。
      • 提供多樣的運算方法與高效能。
    • 注意事項:
      • 使用 [] 時需注意邊界,建議用 at() 提高安全性。
      • 大量運算時可能因頻繁調整大小而影響效能。

參考資料

使用 vector

C++ vector Library Reference (vector functions)

以範圍為基礎的 for 陳述式 (C++) | Microsoft Learn

註標運算子:[] | Microsoft Learn

C++ Vectors

Vector erase() in C++ STL - GeeksforGeeks

C++ std::vector 用法與範例 | ShengYu Talk

資料結構筆記:C++中的迭代器 iterator - hifone2191的創作 - 巴哈姆特

C++ vector 容器 | 菜鸟教程