作者: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