HOWTO · C++
如何在 C++ 中建立向量的向量
說明如何在 C++ 中建立指定列數與欄數的向量的向量,填入範例值並修改元素。
本頁內容
向量的向量是將多個 std::vector 列放在外層 std::vector 中。若列數與欄數已知,可以建立外層向量,並以包含欄數和初始值的內層向量作為每一列。本文會示範如何建立指定尺寸的網格、填入範例值,以及更新其中的元素。當每一列都適合使用向量表示,且列數或欄數由程式決定時,這種結構便很實用。
使用指定大小與初始值的建構函式在 C++ 中建立向量的向量
指定大小與初始值的建構函式會明確設定兩個維度和初始內容。例如,std::vector<std::vector<int>> grid(rows, std::vector<int>(columns, 0)); 會建立 rows 個內層向量,每個向量都包含 columns 個初始值為零的整數。內層向量會建構一次,再作為初始化外層向量各列的值。這是同時指定大小和初始值的建構方式,不是預設建構。
以下範例建立四列、每列六個整數。向量索引從零開始,因此 [2][2] 指向第三列第三欄;巢狀呼叫 .at() 則指向第四列第四欄。.at() 會分別檢查每個索引是否小於該向量的大小;若索引不指向有效元素,就會回報越界存取。當索引已知有效時,使用中括號會更簡潔。
#include <iostream>
#include <vector>
int main() {
constexpr int LENGTH = 4;
constexpr int WIDTH = 6;
std::vector<std::vector<int>> grid(LENGTH, std::vector<int>(WIDTH, 0));
grid[2][2] = 12;
std::cout << grid[2][2] << '\n';
grid.at(3).at(3) = 99;
std::cout << grid[3][3] << '\n';
return 0;
}
12
99
這兩個輸出由程式中的兩次指定決定。列與欄都要使用各自維度內的索引:外層向量用來選取列,該列的內層向量則用來選取欄。如果維度不是固定值,也可以從程式資料取得列數和每列的大小。
使用 rand 函式在 C++ 中以範例值填入向量的向量
建立網格後,可以用巢狀迴圈走訪每個整數並指定範例值。下方程式會以目前時間為 rand 設定種子,再用 % 100 產生 0 到 99 之間的值。每次執行時列印的值可能不同,因此沒有固定輸出可供照抄。範例使用 <cstdlib> 提供 rand 和 srand,並使用 <ctime> 提供 std::time。
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>
int main() {
constexpr int LENGTH = 4;
constexpr int WIDTH = 6;
std::vector<std::vector<int>> grid(LENGTH, std::vector<int>(WIDTH, 0));
std::srand(static_cast<unsigned int>(std::time(nullptr)));
for (auto& row : grid) {
for (int& value : row) {
value = std::rand() % 100;
std::cout << value << ' ';
}
std::cout << '\n';
}
return 0;
}
這種方式適合產生示範資料或處理小型、非敏感的工作。rand 不適合用於加密用途。此外,除非產生器可能回傳的值數量能被 100 整除,否則取餘數可能使結果分布產生偏差。若模擬或應用程式需要更好的分布特性,應改用符合需求的亂數工具,不要把這個簡短範例當成通用的亂數產生器。
使用巢狀範圍迴圈修改向量的向量中的每個元素
範圍迴圈會逐列走訪向量,內層迴圈則會走訪該列中的每個整數。在 int& value 中,& 表示 value 是儲存元素的參考,因此對它指定新值會直接修改向量。若沒有參考,迴圈變數就會是副本,修改它不會改變向量中儲存的整數。以下程式會先列印網格,再將每個元素乘以三後列印一次。
#include <iostream>
#include <vector>
void print(const std::vector<std::vector<int>>& grid) {
for (const auto& row : grid) {
for (int value : row) {
std::cout << value << ' ';
}
std::cout << '\n';
}
}
int main() {
std::vector<std::vector<int>> grid{{1, 2, 3}, {4, 5, 6}};
std::cout << "Before:\n";
print(grid);
for (auto& row : grid) {
for (int& value : row) {
value *= 3;
}
}
std::cout << "After:\n";
print(grid);
return 0;
}
每個內層向量各自管理一串整數,外層向量則儲存這些列向量。同一列中的整數在記憶體中連續排列,但整個巢狀結構並不是單一連續的二維區塊。這只描述資料的儲存方式,並不代表一般性的速度比較;實際效能取決於操作和工作負載。若各列本來就要分開處理,或需要一般向量操作,向量的向量便很實用。若工作明確要求整塊連續的儲存空間,則應選擇專為這種配置設計的表示方式。