作者:billy
版權聲明:著作權歸作者所有,商業轉載請聯繫作者獲得授權,非商業轉載請註明出處
簡介
向量(Vector)是一個封裝了動態大小數組的順序容器(Sequence Container)。跟任意其它類型容器一樣,它能夠存放各種類型的對象。可以簡單的認爲,向量是一個能夠存放任意類型的動態數組。當程序員無法知道自己需要的數組的規模多大時,用 vector 來解決問題可以達到最大節約空間的目的。
vector 的動態擴充機制
vector是一塊連續分配的內存,從數據安排的角度來講,和數組極其相似, 不同的地方就是:
- 數組是靜態分配空間,一旦分配了空間的大小,就不可再改變了;
- 而 Vector 是動態分配空間,隨着元素的不斷插入,它會按照自身的一套機制不斷擴充自身的容量;
vector的擴充機制:按照容器現在容量的一倍進行增長。 vector容器分配的是一塊連續的內存空間,每次容器的增長,並不是在原有連續的內存空間後再進行簡單的疊加, 而是重新申請一塊更大的新內存,並把現有容器中的元素逐個複製過去,然後銷燬舊的內存。 這時原有指向舊內存空間的迭代器已經失效,所以當操作容器時,迭代器要及時更新。
vector 中 size、capacity、max_size 的區別
- size:當前vector容器真實佔用的大小,也就是當前擁有多少個容器;
- capacity:表示在發生 realloc 前能允許的最大元素數,也可以理解爲預分配的內存空間。例如一個 vector<int> v 的 capacity 爲10,當插入第11個元素時,vector 會 realloc,vector 內部數據會複製到另外一個內存區域。這樣之前指向 vector 中的元素的指針、迭代器等等均會失效;
- max_size:表示容器允許的最大元素數。通常這個數是一個很大的常整數,可以理解爲無窮大,這個數目與平臺和實現相關。因爲 max_size 很大,所以基本不會發生元素數超過 max_size 的情況;
size 和 capacity 兩個屬性分別對應兩個方法:resize() 和 reserve()
- 使用 resize() 容器內的對象內存空間是真正存在的;
- 使用 reserve() 僅僅只是修改了 capacity 的值,容器內的對象並沒有真實的內存空間(空間是"野"的)。此時切記不要使用 [] 操作符訪問容器內的對象,很可能出現數組越界的問題;
示例:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
cout << "v.size() == " << v.size() << ", v.capacity() = " << v.capacity() << endl;
v.reserve(10);
cout << "v.size() == " << v.size() << ", v.capacity() = " << v.capacity() << endl;
v.resize(10);
v.push_back(0);
cout << "v.size() == " << v.size() << ", v.capacity() = " << v.capacity() << endl;
return 0;
}
運行結果:
v.size() == 0, v.capacity() = 0 //初始化完成,但是容器中沒有對象,也沒有預留內存空間
v.size() == 0, v.capacity() = 10 //reserve(10),預留10個對象的空間,但是容器內依然沒有對象,如果使用 [] 訪問會報越界錯誤
v.size() == 11, v.capacity() = 20 //resize(10),容器內的對象空間爲10個對象的空間,此時再添加一個對象,就要重新分配一次空間,容量爲原先的一倍。並把現有容器中的元素逐個複製過去,然後銷燬舊的內存
注意:capacity 和 reserve 只適用於 string 和 vector,STL容器中擁有 capacity 屬性的只有 string 和 vector。
常用函數
- 構造
- vector():創建一個空vector
- vector(int nSize):創建一個vector,元素個數爲nSize
- vector(int nSize, const t& t):創建一個vector,元素個數爲nSize,且值均爲t
- vector(const vector&):複製構造函數
- vector(begin, end):複製 [begin,end) 區間內另一個數組的元素到vector中
- 新增
- void push_back(const T& x):向量尾部增加一個元素X
- iterator insert(iterator it, const T& x):向量中迭代器指向元素前增加一個元素x
- iterator insert(iterator it, int n, const T& x):向量中迭代器指向元素前增加n個相同的元素x
- iterator insert(iterator it, const_iterator first, const_iterator last):向量中迭代器指向元素前插入另一個相同類型向量的 [first,last) 間的數據
- 刪除
- iterator erase(iterator it):刪除向量中迭代器指向元素
- iterator erase(iterator first, iterator last):刪除向量中 [first,last) 中元素
- void pop_back():刪除向量中最後一個元素
- void clear():清空向量中所有元素
- 遍歷
- reference at(int pos):返回pos位置元素的引用
- reference front():返回首元素的引用
- reference back():返回尾元素的引用
- iterator begin():返回向量頭指針,指向第一個元素
- iterator end():返回向量尾指針,指向向量最後一個元素的下一個位置
- reverse_iterator rbegin():反向迭代器,指向最後一個元素
- reverse_iterator rend():反向迭代器,指向第一個元素之前的位置
- 大小
- int size() const:返回向量中元素的個數
- int capacity() const:返回當前向量所能容納的最大元素值
- int max_size() const:返回最大可允許的vector元素數量值
- 其他
- bool empty() const:判斷向量是否爲空,若爲空,則向量中無元素
- void swap(vector&):交換兩個同類型向量的數據
- void assign(int n, const T& x):設置向量中第n個元素的值爲x
- void assign(const_iterator first, const_iterator last):向量中 [first,last) 中元素設置成當前向量元素
綜合運用示例
mymatrix.h
#ifndef MYMATRIX_H
#define MYMATRIX_H
#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
template <class T>
class MyMatrix1f // 列向量類
{
public:
MyMatrix1f() // 無參構造函數
{
matrix.reserve(3);
}
MyMatrix1f(T x, T y) // 有參構造函數
{
matrix.reserve(3);
matrix.push_back(x);
matrix.push_back(y);
matrix.push_back(1);
}
MyMatrix1f(const MyMatrix1f& vec) // 拷貝構造函數
{
matrix.reserve(vec.matrix.size());
for (auto &temp : vec.matrix)
{
matrix.push_back(temp);
}
}
T operator()(size_t index) // 重載運算符()
{
if (index >= matrix.size())
{
cout << "Out of range !" << endl;
return 0;
}
return matrix.at(index);
}
void push(T value) // 列向量添加元素
{
matrix.push_back(value);
}
void print() // 打印列向量所有元素
{
for (auto &vec : matrix)
{
cout << vec << "\t";
}
cout << endl;
}
private:
vector<T> matrix;
};
template <class T>
class MyMatrix3f: public vector<vector<T>> // 3x3變換矩陣類
{
public:
MyMatrix3f(T h, T k, T a): vector<vector<T>>(0) //有參構造函數
{
vector<T> v1, v2, v3;
v1.reserve(3);
v2.reserve(3);
v3.reserve(3);
v1.push_back(static_cast<T>( cos(a) ));
v1.push_back(static_cast<T>( sin(a) * (-1) ));
v1.push_back(h);
v2.push_back(static_cast<T>( sin(a) ));
v2.push_back(static_cast<T>( cos(a) ));
v2.push_back(k);
v3.push_back(0);
v3.push_back(0);
v3.push_back(1);
this->reserve(3);
this->push_back(v1);
this->push_back(v2);
this->push_back(v3);
}
T operator()(size_t x, size_t y) // 重載運算符()
{
if (x >= this->size())
{
cout << "Out of range !" << endl;
return 0;
}
vector<T> vec = this->at(x);
if (y >= vec.size())
{
cout << "Out of range !" << endl;
return 0;
}
return vec.at(y);
}
MyMatrix1f<T> operator*(MyMatrix1f<T>& matrix) // 重載運算符*
{
MyMatrix1f<T> ret;
for (auto &vec : *this)
{
T value = 0;
size_t i = 0;
for(auto &temp : vec) // 矩陣乘法運算 - 矩陣的每一行乘以列向量的和成爲一個新的列向量
{
value += temp * matrix(i);
i++;
}
ret.push(value);
}
return ret;
}
void print() // 打印3x3變換矩陣所有元素
{
for (auto &vector : *this)
{
for (auto &vec : vector)
{
cout << vec << "\t\t";
}
cout << endl;
}
}
};
#endif // MYMATRIX_H
main.cpp
#include "mymatrix.h"
int main()
{
MyMatrix1f<double> matrix1f(2, 4);
matrix1f.print();
cout << "matrix1f(1): " << matrix1f(1) << endl << endl;
MyMatrix3f<double> matrix3f(10.0, 20.0, M_PI/3);
matrix3f.print();
cout << "matrix3f(1,2): " << matrix3f(1,2) << endl << endl;
MyMatrix1f<double> ret = matrix3f*matrix1f;
ret.print();
return 0;
}
運行結果:
2 4 1
matrix1f(1): 4
0.5 -0.866025 10
0.866025 0.5 20
0 0 1
matrix3f(1,2): 20
7.5359 23.7321 1