STL vector用法詳解

2020-07-16 10:04:38
標準模板庫(STL)是程式設計師定義的資料型別和演算法的集合,可供 C++ 程式使用。這些資料型別和演算法不是 C++ 語言的一部分,但它們的建立是對內建資料型別的有益補充。如果打算繼續在電腦科學領域學習,那麼就應該熟悉 STL。本節介紹 STL 資料型別之一:向量(vector)

注意,要使用向量,則程式的標頭檔案必須指明使用 namespacestd,因為向量包含在該名稱空間中。許多較早的編譯器不允許名稱空間或不支援 STL。

在 STL 中定義的資料型別通常稱為容器。之所以稱為容器,是因為它們儲存和組織資料。STL 中有兩種型別的容器:順序容器和關聯容器:
  1. 順序容器以序列方式組織資料,類似於陣列;
  2. 關聯容器使用關鍵字組織資料,它允許對儲存在容器中的元素進行快速隨機存取;

vector 資料型別是一個序列容器,它很像一個一維陣列,其表現和陣列相似的地方如下:
  • 向量包含一系列值或元素。
  • 向量將其元素儲存在連續的記憶體位置中。
  • 可以使用陣列下標運算子[]存取向量中的各個元素。

但是,向量相對於陣列還有幾個優點,比如說:
  • 不必宣告向量將具有的元素的數量。
  • 如果向已滿的向量新增值,則向量將自動增加其大小以適應新值。
  • 向量可以報告它們包含的元素的數量。

vector定義和初始化

要在程式中使用向量,則必須使用以下語句包含 vector 標頭檔案:

#include <vector>

建立向量物件的語法與定義一個常規變數或陣列所用的語法有所不同。以下是一個例子:

vector<int> numbers;

這個語句將 numbers 定義為一個 int 的向量。請注意,資料型別包含在尖括號內,緊跟在單詞 vector 之後。由於向量的大小隨著新增值而擴大,因此不需要宣告大小。不過,如果願意的話,也可以宣告一個開始大小。範例如下:

vector<int> numbers(10);

這個語句將 numbers 定義為 10 個整數的向量,但這只是一個起始大小。如果新增 10 個以上的值,它的大小將會擴大。

注意,如果為向量指定開始大小,則大小宣告符將被括在圓括號中,而不是方括號。

為向量指定開始大小時,還可以指定一個初始化值。初始化值被複製到每個元素。範例如下:

vector<int> numbers (10, 2);

在這個語句中,numbers 被定義為 10 個整數的向量,並且 numbers 中的每個元素都被初始化為值 2。

也可以用另一個向量中的值初始化一個向量。例如,如果 set1 是已經有值的 int 向量,則以下語句將建立一個名為 set2 的新向量,它是 set1 的精確副本:

vector<int> set2(set1);

在執行這個語句之後,向量 set2 將具有相同數量的元素,並保持與 set1 相同的一組值。如果使用的是 C++ 11 版本,則還可以使用一個值列表來初始化 vector,範例如下:

vector<int> numbers { 10, 20, 30, 40 };

該語句定義了一個名為 numbers 的 int 向量。該向量有 4 個元素,其初始化值為 10, 20, 30 和 40。注意,初始化列表被括在一組大括號中,但是在它前面不使用賦值運算子(=)。表 1 總結了前面討論的向量定義過程。

表 1 vector定義範例
定義格式 描 述
vector<string> names; 將 names 定義為 string 物件的空向量
vector<int> scores (15); 將 scores 定義為 15 個整數的向量
vector<char> letters (25, 'A'); 將 letters 定義為 25 個字元的向量。每個元素都用 'A' 初始化
vector<double> values2(values1); 將 values2 定義為 double 向量。value1 的所有元素(也是 double 向量)將被複製到 value2
vector<int> length{12, 10, 6}; 在 C++ 11 中,該語句定義 length 為 3 個 int 值的向量,儲存值 12、10 和 6

儲存和檢索 vector 中的值

要將值儲存到已存在的向量元素中,或存取向量元素中儲存的資料,可以使用陣列下標運算子 []。下面的程式演示了該操作:
//This program stores employee hours worked
// and hourly pay rates in two parallel vectors.
#include <iostream>
#include <iomanip>
#include <vector>    // Needed to use vectors
using namespace std;

int main()
{
    const int NUM_EMPS = 5;    // Number of employees
    vector <int> hours(NUM_EMPS);    // Define a vector of integers
    vector <double> payRate(NUM_EMPS); // Define a vector of doubles
    double grossPay;    // An employee's gross pay
   
    // Get employee work data
    cout << "Enter the hours worked and hourly pay rates of " << NUM_EMPS << " employees. n";
    for (int index = 0; index < NUM_EMPS; index++)
    {
        cout <<"nHours worked by employee #" << (index + 1) << ": ";
        cin >> hours[index];
        cout << "Hourly pay rate for employee #" << (index +1) << ": ";
        cin >> payRate[index];
    }
    //Display each employeeA s gross pay
    cout << "nHere is the gross pay for each employee: n" ;
    cout << fixed << showpoint << setprecision (2);
    for (int index = 0; index < NUM_EMPS; index++)
    {
        grossPay = hours[index] * payRate[index];
        cout << "Employee #" << (index + 1);
        cout << ": $" << setw(7) << grossPay << endl;
    }
    return 0;
}
程式輸出結果為:

Enter the hours worked and hourly pay rates of 5 employees.

Hours worked by employee #1: 10
Hourly pay rate for employee #1: 9.75

Hours worked by employee #2: 15
Hourly pay rate for employee #2: 8.62

Hours worked by employee #3: 20
Hourly pay rate for employee #3: 10.50

Hours worked by employee #4: 40
Hourly pay rate for employee #4: 18.75

Hours worked by employee #5: 40
Hourly pay rate for employee #5: 15.65

Here is the gross pay for each employee:
Employee #1: $  97.50
Employee #2: $ 129.30
Employee #3: $ 210.00
Employee #4: $ 750.00
Employee #5: $ 626.00

下面來分析程式中的某些程式碼。首先看第 5 行,它包含使用向量所必需的前處理器指令:

#include <vector>

在第 11 行和第 12 行中的以下語句定義了兩個向量:

vector<int> hours (NUM_EMPS) ;    // 定義整數向量
vector<double> payRate (NUM_EMPS) ;    // 定義雙精度型別向量

在第 17 行 for 迴圈開始,它的目的是輸入使用者資料。在第 20 行和第 22 行,迴圈使用了相同的語句,讀取輸入並將它們放入向量元素中,這些向量元素由迴圈控制變數 index 的當前值指定。

由於在每個向量名稱後面跟著一個大小宣告符,所以這兩個向量都將按指定的大小建立。在此範例中,命名常數 NUM_EMPS 等於 5,所以兩個向量一開始都有 5 個元素。因為它們已經有元素了,所以可以使用 [] 運算子從元素中讀取值或給元素賦值,這與使用陣列元素的方式完全一樣。

cin >> hours[index];
cin >> payRate [index];

在第 27 行中開始第 2 個 for 迴圈,它的目的是計算並顯示每個員工的總收入。在第 29 行,該迴圈的語句執行該計算,使用的資料來自於每個向量的特定元素。

grossPay = hours[index] * payRate[index];

只要向量已經定義並且擁有給定的起始元素,就可以像使用陣列一樣存取它們,儲存和檢索其資料。

遍歷vector

在 C++11 版本中,程式設計師可以使用基於範圍的 for 迴圈遍歷向量中的元素,下面的程式演示了其用法:
// This program uses two range-based for loops with a vector.
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    // Define a vector with a starting size of 5 elements
    vector<int>numbers(5);
    // Get values for the vector elements
    // Make the range variable a reference variable so it can be
    // used to change the contents of the element it references.
    for (int &val : numbers)
    {
        cout << "Enter an integer value: ";
        cin >> val;
    }

    // Display the vector elements
    cout << "nHere are the values you entered: n";
    for (int val : numbers)
        cout <<val <<" ";
    cout << endl;
    return 0;
}
程式輸出結果:

Enter an integer value: 10
Enter an integer value: 20
Enter an integer value: 30
Enter an integer value: 40
Enter an integer value: 50

Here are the values you entered:
10 20 30 40 50

vector push_back 成員函數

不能使用 [] 運算子來存取尚不存在的向量元素。要將值儲存在沒有起始大小或已滿的向量中,應使用 push_back 成員函數。該函數接受一個值作為實參,並將其儲存在位於向量末尾的新元素中。

以下是一個使用 push_back 函數,將一個元素新增到一名為 numbers 的 int 向量的例子:

numbers.push_back(25);

該語句可以建立一個新的元素,其儲存的值為 25,該元素被放在 numbers 向量的末尾。如果 numbers 以前沒有元素,則新元素將成為其單一元素。

下面的程式允許使用者指定員工的數量。hours 和 payRate 這兩個向量並沒有定義開始大小。由於這些向量沒有起始元素,因此需要使用 push_back 成員函數來儲存值。
// This program stores employee hours worked and hourly pay rates
// in two vectors. It demonstrates the use of the push_back member
// function to add new elements to the vectors.
#include <iostream>
#include <iomanip>
#include <vector>
// Needed to use vectors

using namespace std;

int main()
{
    vector<int> hours;    // hours is an empty integer vector
    vector<double> payRate; // payRate is an empty double vector
    double grossPay;
    int numEmp1oyees;    // Number of employees
    int index;    // Loop counter

    // Get the number of employees
    cout << "How many employees do you have?";
    cin >> numEmp1oyees;
    // Input the payroll data
    cout << "Enter the hours worked and hourly pay rates of the "<< numEmployees << " employees. n" ;
    for (index = 0; index < numEmployees; index++)
    {
        int tempHours;    // Number of hours entered
        double tempRate; 丨丨 Pay rate entered
        cout << "Hours worked by employee #" << (index + 1) << ":";
        cin >> tempHours;
        hours.push_back(tempHours); // Add an element to hours
        cout << "Hourly pay rate for employee #" << (index + 1) << ": ";
        cin >> tempRate;
        payRate.push_back(tempRate); // Add an element to payRate
    }

    //Display each employeeT s gross pay
    cout << "nHere is the gross pay for each employee: n";
    cout << fixed << showpoint << setprecision (2);
    for (index = 0; index < numEmployees; index++)
    {
        grossPay = hours[index] * payRate[index];
        cout << "Employee #" << (index + 1);
        cout << " $" << setw (7) << grossPay << endl;
    }
    return 0;
}
程式輸出結果:

How many employees do you have?3
Enter the hours worked and hourly pay rates of the 3 employees.
Hours worked by employee #1:40
Hourly pay rate for employee #1: 12.63
Hours worked by employee #2:25
Hourly pay rate for employee #2: 10.35
Hours worked by employee #3:45
Hourly pay rate for employee #3: 22.65

Here is the gross pay for each employee:
Employee #1 $ 505.20
Employee #2 $ 258.75
Employee #3 $1019.25

程式中第 39?44 行中的迴圈可以計算並顯示每個員工的總收入,它使用 [] 運算子來存取 hours 和 payRate 向量的元素。之所以可以這樣做,是因為第 24?34 行中的第一個迴圈已經使用了 push_back 成員函數來建立兩個向量中的元素。

vector size成員函數

與陣列不同,向量可以報告它們包含的元素的數量,這是通過 size 成員函數實現的。以下是一個使用 size 成員函數的範例:

numValues = set.size();

在該語句中,假定 numValues 是一個 int,set 是一個向量。執行語句後,numValues 將包含 set 中的元素數量。

在編寫接收向量作為實參的函數時,size 成員函數特別有用。例如,來看 showValues 函數的以下程式碼:
void showValues(vector<int> vect)
{
    for (int count = 0; count < vect.size(); count++)
        cout << vect[count] << endl;
}
因為向量可以報告其大小,所以該函數不需要第二個引數來表示向量中元素的個數。下面的程式演示了該函數的應用:
//This program demonstrates the vector size member function.
#include <iostream>
#include <vector>
using namespace std;

// Function prototype

void showValues(vector<int>);

int main()
{
    vector<int> values;
    // Store a series of numbers in the vector
    for (int count = 0; count < 7; count++)
        values.push_back(count * 2);
    // Display the numbers
    showValues(values);
    return 0;
}
void showValues(vector<int> vect)
{
    for (int count = 0; count < vect.size(); count++)
        cout << vect[count] << " ";
    cout << endl;
}
程式輸出結果:

0 2 4 6 8 10 12

程式中在定義向量時,並未給定元素,所以在將值儲存到向量中時,使用了 push_back 函數。每次被呼叫時,push_back 函數都將建立一個新的向量元素來儲存值。

vector pop_back成員函數

要從向量中刪除最後一個元素,可以使用 pop_back 成員函數。以下語句從名為 collection 的向量中移除最後一個元素:

collection.pop_back();

下面的程式演示了 pop_back 函數:
//This program demonstrates the vector size,
//push_back, and pop_back member functions.
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> values;
    // Store values in the vector
    values.push_back(1);
    values.push_back(2);
    values.push_back(3);
    cout << "The size of values is " << values.size () << endl;
    // Remove a value from the vector
    cout << "Popping a value from the vector...n";
    values.pop_back();
    cout << "The size of values is now " << values.size () << endl;
    // Now remove another value from the vector
    cout << "Popping a value from the vector...n";
    values.pop_back();
    cout << "The size of values is now " << values.size() << endl;
    // Remove the last value from the vector
    cout << "Popping a value from the vector...n"; values.pop_back();
    cout << "The size of values is now " << values.size () << endl;
    return 0;
}
程式輸出結果:

The size of values is 3
Popping a value from the vector...
The size of values is now 2
Popping a value from the vector...
The size of values is now 1
Popping a value from the vector...
The size of values is now 0

注意,pop_back 函數是一個 void 函數,它不返回將從向量中刪除的值。以下程式碼行將不起作用:

cout << "The value being removed from the vector is "<<values.pop_back() << endl; // Error!

vector clear成員函數

要完全清除向量的內容,可以使用 clear 成員函數,如下例所示:

numbers.clear();

在執行該語句之後,numbers 的所有元素都將被清除。下面的程式演示了該函數的用法:
//This program demonstrates the vector clear member function.
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> values(100);
    cout << "The values vector has " << values.size() << " elements.n";
    cout << "will call the clear member function. . . n";
    values.clear();
    cout << "Now the values vector has "<< values.size() << " elements . n";
    return 0;
}
程式輸出結果:

The values vector has 100 elements.
will call the clear member function. . .
Now the values vector has 0 elements .

vector empty成員函數

要確定一個向量是否為空,可以使用 empty 成員函數。如果向量為空,則該函數將返回 true;如果向量中儲存有元素,則返回 false。假設 numberVector 是一個向量,以下是其應用範例:
if (numberVector.empty())
    cout << "No values in numberVector. n";
下面的程式顯示了如何傳遞一個向量給函數。該函數名為 avgVector,演示了 empty 成員函數的用法。
//This program demonstrates the vector empty member function.
#include <iostream>
#include <vector>
using namespace std;

// Function prototype
double avgVector(vector<int>);

int main()
{
    vector<int> values;    // Define a vector to hold int values
    int numValues;    // Number of values to be averaged
    double average;    // Average of the stored values
    //Get the number of values    to average
    cout << "How many values do you wish to average?";
    cin >> numValues;
    // Get the values and store    them in a vector
    for (int count = 0; count <    numValues; count++)
    {
        int tempValue;
        cout << "Enter an integer value:";
        cin >> tempValue;
        values.push_back(tempValue);
    }
    // Get the average of the values and display it
    average = avgVector(values);
    cout << "Average: " << average << endl;
    return 0;
}

double avgVector(vector<int> vect)
{
    int total = 0;    // Accumulator
    double avg = 0.0;
    if (vect.empty())    // Determine if the vector is empty
        cout << "No values to average. n";
    else
    {
        for (int count = 0; count < vect.size(); count++)
            total += vect[count];
            avg = static_cast<double>(total)/vect.size();
    }
    return avg;
}
程式輸出結果:

How many values do you wish to average?4
Enter an integer value:12
Enter an integer value:3
Enter an integer value:7
Enter an integer value:9
Average: 7.75

vector成員函數彙總

表 2 提供了有關向量成員函數的匯總資訊,其中有一些在已經討論過,另外還有一些是新新增的。

表 2 vector成員函數彙總
成員函數 描 述
at(position) 返回 vector 中位於 position 位置的兀素的值。範例:
x = vect. at (5) ; //將 vect [5] 的值賦給 x
capacity() 返回在不重新分配額外記憶體的情況下,可能儲存在向量中的最大元素數量(它和由 size 成員函數返回的值並不是一回事)。範例:
x = vect. capacity () ; //將 vect 的容量賦值給 x
clear() 清除向量的所有元素。範例:
vect .clear () ; //從 vect 中移除所有兀素
empty() 如果 vector 是空的,則返回 true。否則,它返回 false。範例:
if (vect. empty () ; //如果該向量是空的
    cout << "The vector is empty.";
pop_back() 從向量中刪除最後一個元素。範例:
vect.pop_back () ; //移除 vect 的最後一個元素,大小減去1
push_back(value) 在向量的最後一個元素中儲存一個值。如果向量已滿或為空,則會建立一個 新元素。範例:
vect.push_back (7) ; //在 vect 的最後一個元素中儲存 7
reverse() 反轉向量中元素的順序(最後一個元素變成第一個元素,第一個元素成為最後一個元素)。範例:
vect. reverse () ; //反轉 vect 中元素的順序
resize(n)
resize(n, value)
調整向量的大小以使其具有 n 個元素,其中 n 大於向量的當前大小。如果包含可選的引數 value,則每個新元素都將使用該 value 值進行初始化。 vect 當前已有 4 個元素情況下的範例:
vect. resize (6, 99) ; //將兩個元素新增到向量的末尾,每個元素初始化為 99
size() 返回向量中元素的數量。範例:
numElements = vect.size();
swap(vector2) 將向量的內容與 vector2 的內容交換。範例:
vect1.swap (vect2) ; //交換 vect1 和 vect2 的內容