使用 vector


如果需要線性、長度可變的資料容器,可以使用 vector,這需要包含 vector 標頭檔:

#include <vector>

技術上來說,vector 是個類別模版(class template),不過使用上,只需要知道,vector 可以裝載指定型態的資料。例如,建立一個可裝載 intvector<int>

vector<int> number;

這會建立一個空的 vector<int>,如果想在建立容器時裝載指定的元素,可以使用清單初始化(list initialization)或者初始器(Initializer):

vector<int> number = {10, 20, 30};
vector<double> score{85.5, 78.2, 63.0};

想要循序地走訪 vector 中的元素,可以使用 for range 語法,例如:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> number = {10, 20, 30};

    for(auto n : number) {
        cout << n << endl;
    }

    return 0;
}

透過 [] 指定索引可以存取特定位置的元素,例如:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> number = {10, 20, 30};

    for(int i = 0; i < number.size(); i++) {
        cout << number[i] << endl;
    }

    return 0;
}

可以從 vectorsize 方法得知元素的個數,empty 方法可以得知是否為空,front 方法可以取得第一個元素,back 方法可以取得最後一個元素,想要新增元素,可以使用 push_backinsert 方法,想取出最後一個元素可以用 pop_backclear 可以清空 vector 等。

底下會顯示 9 到 0 的數字:

#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;
}

建立 vector 時可以指定初始的長度,每個元素會被初始為指定型態的零值,例如底下會建立長度為 10 的 vector,元素初值都是 0:

vector<int> v1(10);

也可以在指定初始長度的同時,指定每個元素的初值,例如底下會建立長度為 10 的 vector,元素初值都是 5:

vector<int> v1(10, 5);

vector 可以使用另一個 vector 作為引數來建構,例如以 v1 作為引數來建構 v2

vector<int> v1 = {10, 20, 30};
vector<int> v2(v1);

這會將 vector 的元素複製給被指定的 vectorvector 可以指定給另一 vector,這也會將 vector 的元素複製給被指定的 vector,例如:

vector<int> v1 = {10, 20, 30};
vector<int> v2 = v1;

若要指定來源 vector 的某個範圍建構出新的 vector,必須指定起始位置的 iterator 與結束位置的iterator,例如底下從索引 2 開始走訪至尾端的元素,用以建立新的 vector

vector<int> v1 = {10, 20, 30, 40, 50};
vector<int> v2(v1.begin() + 2, v1.end()); // 包含 30, 40, 50

在上頭,beginend 方法分別傳回起始位置的 vector<int>::iterator 與結束位置的 vector<int>::iterator,可以把它們看成代表首個元素與最後一個元素的位置,對它們進行 +- 運算,表示元素的位移量,操作上很像指標,至於是不是真的指標,要看底層的實作而定。

就 API 的設計來說,不建議將 beginend 方法的傳回值看成是指標,而建議將之看成迭代器(iterator),這些迭代器重載了相關的運算子,令其看來像是指標操作,因為容器相關的程式庫,為基於這類操作協定,令提供的 API 具有通用性。

若要使用迭代器來走訪元素,例如,先前的 for range 語法,若要使用 beginend 方法,可以搭配 for 迴圈,例如:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> number = {10, 20, 30};

    for(vector<int>::iterator it = number.begin();
        it != number.end();
        it++) {
        auto n = *it;
        cout << n << endl;
    }

    return 0;
}

類似地,若要使用陣列的元素來建構 vector,可以透過以下的方式:

int number[] = {10, 20, 30, 40, 50};
vector<int> v(begin(number) + 2, end(number)); // 包含 30, 40, 50

如果打算對 vector 進行排序、尋找、反轉等操作,可以使用包含 algorithm 標頭檔:

#include <algorithm>

一些操作會使用到迭代器,例如下面這個程式直接示範了排序、尋找、反轉等操作:

#include <algorithm>
#include <iostream> 
#include <vector>
using namespace std; 

int main() { 
    vector<int> number = {30, 12, 55, 31, 98, 11, 41, 80, 66, 21};

    // 排序 
    sort(number.begin(), number.end());
    for(auto n : number) {
        cout << n << " ";
    }
    cout << endl;

    cout << "輸入搜尋值:";
    int search = 0;
    cin >> search;

    vector<int>::iterator it = find(number.begin(), number.end(), search);
    cout << (it != number.end() ? "找到" : "沒有")
         << "搜尋值" 
         << endl;

    // 反轉 
    reverse(number.begin(), number.end());
    for(auto n : number) {
        cout << n << " ";
    }
    cout << endl;

    return 0; 
}

執行結果:

11 12 21 30 31 41 55 66 80 98
輸入搜尋值:22
沒有搜尋值
98 80 66 55 41 31 30 21 12 11