纵有疾风起,人生不言弃。本文篇幅较长,如有错误请不吝赐教,感谢支持。
vector的数据安排以及操作方式,与array非常相似,都是一片连续的储存空间,两者的唯一差别在于空间的运用的灵活性。
array是静态数组,一旦配置了空间就无法再改变,要换大一点或者小一点的空间,可以,一切琐碎得由自己来,首先配置一块新的空间,然后将旧空间的数据搬往新空间,再释放原来的空间。
vector是动态空间(动态数组),随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。因此vector的运用对于内存的合理利用与运用的灵活性有很大的帮助,我们再也不必害怕空间不足而一开始就要求一个大块头的array了。
①vector的实现技术:
vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率,一旦vector旧空间满了,如果客户每新增一个元素,vector内部只是扩充一个元素的空间,实为不智,因为只要是扩充空间(不论多大),其步骤就是“配置新空间-数据移动-释放旧空间”的大工程,时间成本很高,所以为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求大一些,以备将来可能的扩充,这边是容量的概念。换句话说,一个vector的容量永远大于或等于其大小,一旦容量等于大小,便是满载,下次再有新增元素,整个vector容器就得另觅居所(配置新空间-数据移动-释放旧空间)。
②vector迭代器:
vector维护一个线性空间,所以不论元素的型别如何,普通指针都可以作为vector的迭代器,因为vector迭代器所需要的操作行为,如operaroe*, operator->, operator++, operator–, operator+, operator-, operator+=, operator-=, 普通指针天生具备。vector支持随机存取,而普通指针正有着这样的能力。所以vector提供的是随机访问迭代器(Random Access Iterators).
③vector的数据结构:
vector所采用的数据结构非常简单,线性连续空间,它以两个迭代器_Myfirst和_Mylast分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器_Myend指向整块连续内存空间的尾端。
④注意:
所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可配置的空间),而是分配一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。这是程序员容易犯的一个错误,务必小心。
注:使用vector容器时,需包含头文件#include < vector>
函数 | 解释 |
---|---|
vector< T > v; | 采用模板实现类实现(显示实例化),默认构造函数, |
vector(v.begin(), v.end()); | 将v[begin(), end())区间中的元素拷贝给本身 |
vector(n, elem); | 构造函数将n个elem拷贝给本身。 |
vector(const vector &vec); | 拷贝构造函数,拿另一个vector对象初始化本身 |
实例:vector构造函数
#include
#include
using namespace std;
void printvector(const vector<int>& vec)
{
for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it;
}
cout << endl;
}
int main()
{
vector<int> v1 = { 1,2,3 };//采用模板实现类实现(显示实例化),默认构造函数,
vector<int> v2(6,1);//构造函数将n个elem拷贝给本身。
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
vector<int> v3(arr, arr+sizeof(arr)/ sizeof(arr[0]));//将v[begin(), end())区间中的元素拷贝给本身
vector<int> v4(v1);//拷贝构造函数,拿另一个vector对象初始化本身
printvector(v1);
printvector(v2);
printvector(v3);
printvector(v4);
return 0;
}
函数原型 | 解释 |
---|---|
size_t max_size() const; | 返回容器的最大长度 |
size_t capacity() const; | 返回容器的容量。 |
size_t size() const; | 返回容器的实际大小(已使用的空间)。 |
bool empty() const; | 判断容器是否为空。 |
void clear(); | 清空容器。 |
void reserve(size_t size); | 容器预留size个元素长度,预留位置不初始化,元素不可访问,作用:预开辟空间,避免多次重新分配空间 |
void shrink_to_fit(); | 将容器的容量降到实际大小(需要重新分配内存)。 |
void resize(size_t size); | 把容器的实际大小置为size,如果size<实际大小,会截断多出的部分;如果size>实际大小,则以默认值0填充新位置 |
void resize(size_t size,const T &value); | 把容器的实际大小置为size,如果size<实际大小,会截断多出的部分;如果size>实际大小,就用value填充。 |
实例:reserve和resize辨析:
#include
#include
using namespace std;
void printVector(const vector<int>& vec)//形参使用const,避免被修改
{ //const_iterator只读迭代器
for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it;
}
cout << endl;
}
void test()
{
//1.resize开辟空间,并初始化
//2.reserve开辟空间,但不初始化
vector<int> v2;
v2.push_back(1);//尾部插入一个元素
v2.push_back(2);
v2.push_back(3);
cout << "size:" << v2.size() << endl;
v2.resize(5);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
cout << "size:" << v2.size() << endl;
printvector(v2);
v2.resize(2);//如果容器变短,则末尾超出容器长度的元素被删除。
cout << "size:" << v2.size() << endl;
printvector(v2);
v2.resize(5,6);//如果容器变长,也可以用value填充
cout << "size:" << v2.size() << endl;
printvector(v2);
v2.reserve(20);
v2.push_back(20);
printvector(v2);//容器变长了,但并没有初始化
cout << "size:" << v2.size() << endl;
cout << "capacity:" << v2.capacity() << endl;
//cout << v2[10] << endl;//err,不能访问未初始化的空间
}
int main()
{
test();
return 0;
}
reserve作用:预开辟空间,避免多次重新分配空间
如果不加reserve预开辟空间,我们看看会重新分配多少次空间。
#include
#include
using namespace std;
void test()
{
vector<int> v;
int* p = NULL;
int num = 0;
for (int i = 0; i < 10001000; i++)
{
v.push_back(i);
if (p != &v[0])
{
p = &v[0];
num++;
}
}
cout << "num=" << num << endl;
return 0;
}
int main()
{
test();
return 0;
}
函数原型 | 解释 |
---|---|
T &operator[](size_t n); | 通过[]访问元素,如果越界,不抛异常,程序直接挂掉 |
T &at(size_t n); | 通过at方法获取下标为n的元素,如果n越界,抛出out_of_range异常。 |
T *data(); | 返回容器中动态数组的首地址。 |
const T *data() const; | 返回容器中动态数组的首地址。 |
T &front(); | 返回第一个元素。 |
T &back(); | 返回,最后一个元素。 |
作用:通过重载赋值运算符operator=和成员函数assign(),给已存在的容器赋值,将覆盖容器中原有的内容。
函数原型 | 解释 |
---|---|
vector &operator=(const vector &v); | 把容器v赋值给当前容器。 |
assign(beg, end); | 将[beg, end)区间中的数据拷贝赋值给本身。 |
void assign(const size_t n, const T& value); ; | 将n个value拷贝赋值给本身。 |
void assign(const size_t n, const T& value); | 把n个value给容器赋值。 |
表格一览:
函数原型 | 解释 |
---|---|
void swap(vector &v); | 把当前容器与v交换。交换的是动态数组的地址。作品:收缩内存空间。 |
swap妙用:收缩内存空间
#include
#include
using namespace std;
void test()
{
vector<int> v;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
}
cout << "v的容量:" << v.capacity() << endl;
cout << "v的实际大小:" << v.size() << endl;
cout << "----------------" << endl;
v.resize(10);//将容器的实际大小设置为10,但容量没变
cout << "resize后v的容量:" << v.capacity() << endl;
cout << "resize后v的实际大小:" << v.size() << endl;
cout << "----------------" << endl;
vector<int>(v).swap(v);//匿名对象和v对象交换
//匿名对象调用拷贝构造,匿名对象的容量和实际大小均为10,此时在与v进行交换,做到了收缩内存的目的
cout << "与匿名对象交换后v的容量:" << v.capacity() << endl;
cout << "与匿名对象交换后v的实际大小:" << v.size() << endl;
}
int main()
{
test();
return 0;
}
表格一览:
函数原型 | 解释 |
---|---|
bool operator == (const vector< T > & v) const; | |
bool operator != (const vector< T > & v) const; |
表格一览:
函数原型 | 解释 |
---|---|
iterator insert(iterator pos, const T& ele); | 在指定位置插入一个元素ele 返回指向插入元素的迭代器。 |
iterator insert(const_iterator pos, int count,ele); | 迭代器指向位置pos插入count个元素ele.返回指向插入元素的迭代器。 |
void push_back(const T& ele); | 尾部插入元素ele |
void pop_back(); | 删除最后一个元素 |
iterator erase(const_iterator start, const_iterator end); | 删除迭代器从start到end之间的元素,返回下一个有效的迭代器。 |
iterator erase(const_iterator pos); | 删除迭代器指向的元素,返回下一个有效的迭代器。 |
实例:vector插入和删除操作
#include
#include
using namespace std;
void printVector(const vector<int>& vec)//形参使用const,避免被修改
{ //const_iterator只读迭代器
for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it;
}
cout << endl;
}
void test()
{
vector<int> v;
for (int i = 0; i < 5; i++)
{
v.push_back(i + 1);//尾部插入元素
}
printVector(v);//1 2 3 4 5
v.insert(v.begin() + 1, 2, 100);//在第二个元素前插入2个100
printVector(v);//1 100 100 2 3 4 5
v.pop_back();//尾部删除一个元素
printVector(v);//1 100 100 2 3 4
cout << "-------------" << endl;
v.erase(v.begin());//删除第一个元素
printVector(v);//100 100 2 3 4
vector<int>::const_iterator it=v.erase(v.begin() + 1, v.end() - 1);//删除从第二个元素到倒数第二个元素,返回下一个有效迭代器
printVector(v);//100 4
v.insert(it, 66);
printVector(v);//100 66 4
}
int main()
{
test();
return 0;
}