vector
vector容器的基本概念
vector的数据安排及操作方式,与array非常相似,两者的唯一区别在于空间的运用的灵活性。array是静态空间,一旦配置了就不能改变,要换大一点或者小一点的空间,可以,一切琐碎得有自己来,首先配置一块新的空间,然后将旧空间的数据搬往新的空间,再释放原来的空间。vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新的元素,因此vector的运用对于内存的合理利用与运用的灵活性有很大的帮助,我们再也不比害怕空间不足而一开始就要求一个大块头的array了。
vector的实现技术,关键在于其对大小的控制以及重现配置是的数据移动效率,一旦vector旧空间满了,如果客户每新增一个元素,vector内部只是扩充一个元素的空间,实为不智,因为所谓的扩充空间(不论多大),一如刚所说,是“配置新的空间-移动数据-释放就空间”的大工程,时间成本很高,应该加入某种未雨绸缪的考虑,稍后我们可以看到vector的空间配置策略。
vector迭代器
vector维护一个线性空间,所以不论元素的型别如何,普通指针都可以作为vector的迭代器,因为vector迭代器所需要的操作行为,如operator*,operator->,operator++,operator–,operator+,operator-,operator+=,operator-=,普通指针天生具备,vector支持随机存取,而普通指针正有着这样的能力。所以vector提供的时随机访问迭代器
根据上述描述,如果我们写如下代码:
Vector iterator it1;
Vector iterator it2;
it1的型别其实就是int*,it2的型别其实是teacher*
//An highlighted block
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
for(int i = 0;i<10;i++)
{
v.push_back(i);
cout << v.capacity() << endl; //v.capacity()容器的容量
}
system("pause");
return 0;
}
vector 使用算法来增加容量,这个算法依赖一个经常使用的常对数来实现,这在早些时候会导致分配一些非常小的内存,但是随着 vector 容量的增大,内存增长数也会变大
vector的数据结构
vector所采用的数据结构非常简单,线性连续空间,它以两个迭代器 Myfirst和Mylast分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器Myend指向整块连续内存空间的尾端。
为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求大一些,以备将来可能的扩充,这边是容量的概念,换句话说,一个vector的容量永远大于或等于其大小,一旦容量等于大小,便是满载,下次再有新增元素,整个vector容器就得另觅居所。
注意:
所谓动态增加大小,并不是在原来的空间之后连续的接新空间(因为无法保证原空间之后是否有可配置的空间),而是一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间,因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器都就都失效了。
这是程序员容易犯的一个错误,务必小心
vector常用API操作
vector构造函数
vectorv //采用模板实现类实现,默认构造函数
vector(v.begin(),v.end()) //将v(begin(),end())区间中的元素拷贝给本身
vector(n,elem) //构造函数将n个elem拷贝给本身
vector(); //创建一个空的vector
vector(int nSize) //创建一个vector,元素个数为nSize
vector(int nSize,const t& t) //创建一个vector,元素个数为nSize,且值均为t
vector(const vector&) //复制构造函数
//例子 使用第二个构造函数,我们可以
int arr[] = {1,2,3,4,5,6};
vector<int> v1(arr,arr+sizeof(arr)/sizeof(int));
vector常用赋值操作
assign(beg,end) //将(beg,end)区间的中的数据拷贝赋值给本身
assign(n,elem) //将n个elem拷贝赋值给本身
vector & operator=(const vector &vec) //重载等号操作符
swap(vec) //将vec与本身的元素互换
vector大小操作
size() //返回容器中元素的个数
empty() //判断容器是否为空,若为空,则向量中无元素
resize(int num) //重新指定容器的长度为num,若容器变长,则以默认值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(int num,elem) //重新指定容器的长度为num,若容器变长,则以elem填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
capacity() //容器的容量
reserve(int len)
// vector<double> v;
// v.reserve(20)
// 这样就设置了容器的内存分配,至少可以容纳 20 个元素。
如果当前的容量已经大于或等于 20个元素,那么这条语句什么也不做。
注意,调用 reserve() 并不会生成任何元素。
values 容器这时仍然没有任何元素,直到添加了 20 个元素后,才会分配更多的内存。
调用 reserve() 并不会影响现有的元素。
当然,如果通过调用 reserve() 来增加内存,任何现有的迭代器,
例如开始迭代器和结束迭代器,都会失效,所以需要重新生成它们。
这是因为,为了增加容器的容量,vector<T> 容器的元素可能已经被复制或移到了新的内存地址。
常用函数补充
1.构造函数
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中
2.增加函数
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)间的数据
3.删除函数
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素
4.遍历函数
reference at(int pos):返回pos位置元素的引用
reference front():返回首元素的引用
reference back():返回尾元素的引用
iterator begin():返回向量头指针,指向第一个元素
iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
reverse_iterator rbegin():反向迭代器,指向最后一个元素
reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
5.判断函数
bool empty() const:判断向量是否为空,若为空,则向量中无元素
6.大小函数
int size() const:返回向量中元素的个数
int capacity() const:返回当前向量张红所能容纳的最大元素值
int max_size() const:返回最大可允许的vector元素数量值
7.其他函数
void swap(vector&):交换两个同类型向量的数据
void assign(int n,const T& x):设置向量中第n个元素的值为x
void assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素
8.看着清楚
1.push_back 在数组的最后添加一个数据
2.pop_back 去掉数组的最后一个数据
3.at 得到编号位置的数据
4.begin 得到数组头的指针
5.end 得到数组的最后一个单元+1的指针
6.front 得到数组头的引用
7.back 得到数组的最后一个单元的引用
8.max_size 得到vector最大可以是多大
9.capacity 当前vector分配的大小
10.size 当前使用数据的大小
11.resize 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值
12.reserve 改变当前vecotr所分配空间的大小
13.erase 删除指针指向的数据项
14.clear 清空当前的vector
15.rbegin 将vector反转后的开始指针返回(其实就是原来的end-1)
16.rend 将vector反转构的结束指针返回(其实就是原来的begin-1)
17.empty 判断vector是否为空
18.swap 与另一个vector交换数据
//An highlighted block
void printVector(vector<int> &v)
{
for(vector<int>::iterator it = v.begin();it != v.end();it++)
{
cout << *it << " ";
}
cout << endl;
}
void test2()
{
vector<int> v;
int arr[] = {2,3,4,5,6};
vector <int> v1 (arr,arr+sizeof(arr)/sizeof(int));
vector<int>v2(v1.begin(),v1.end());
printVector(v2);
vector<int>v3(10,100);
printVector(v3);
//赋值使用
vector<int>v4;
v4.assign(v3.begin(),v3.end());
printVector(v4);
v4.swap(v2);
cout << "交换后的v4" << endl;
printVector(v4);
cout << "v4容器的大小:" << v4.size() << endl;
if(v4.empty())
{
cout << "v4空" << endl;
}
else
{
cout << "v4不空" << endl;
}
//v4 23456
v4.resize(10);
printVector(v4);
v4.resize(20,-1); //第二个参数是默认值,默认为0
printVector(v4);
v4.resize(3);
printVector(v4);
}
//An highlighted block
//巧用swap收缩空间
void test3()
{
vector<int>v;
for(int i = 0;i<100000;i++)
{
v.push_back(i);
}
cout << "v的容量:" << v.capacity() << endl;
cout << "v的大小:" << v.size() << endl;
v.resize(3);
cout << "v的容量:" << v.capacity() << endl;
cout << "v的大小:" << v.size() << endl;
//巧用swap
vector<int>(v).swap(v); //利用对象v初始化匿名的vector对象
cout << "v的容量:" << v.capacity() << endl;
cout << "v的大小:" << v.size() << endl;
}
//An highlighted block
//reserve(int len)
void test4()
{
vector<int>v;
int *p = NULL;
int num = 0;
for(int i = 0;i<100000;i++)
{
v.push_back(i);
if(p != &v[0])
{
p = &v[0];
num++;
cout <<"v的容量为:" << v.capacity() << endl;
}
}
cout << "开辟100000用了多少次" << num << endl;
//开辟100000用了多少次
vector<int>v2;
v2.reserve(100000); //预留出空间
int *p1 = NULL;
int num1 = 0;
for(int i = 0;i<100000;i++)
{
v2.push_back(i);
if(p1 != &v2[0])
{
p1 = &v2[0];
num1++;
cout << "v2的容量:" << v2.capacity() << endl;
}
}
cout << "开辟100000用了多少次" << num1 << endl;
}
//An highlighted block
void printVector(vector<int> &v)
{
for(vector<int>::iterator it = v.begin();it != v.end();it++)
{
cout << *it << " ";
}
cout << endl;
}
void test5()
{
vector<int>v;
v.push_back(10);
v.push_back(30);
v.push_back(45);
v.push_back(77);
cout << "v的front:" << v.front() << endl;
cout << "v的back:" << v.back() << endl;
v.insert(v.begin(),2,100);
//参数1 迭代器 参数2 N个数 参数3 具体数
printVector(v);
v.pop_back(); //尾删
printVector(v);
v.erase(v.begin()); //删除
printVector(v);
//v.erase(v.begin(),v.end());
v.clear(); //清空所有数据
if(v.empty())
{
cout << "为空" << endl;
}
v.clear(); //清空所有数据
}
//An highlighted block
void test6()
{
//逆序遍历
vector<int>v;
for(int i = 0;i<10;i++)
{
v.push_back(i);
}
printVector(v);
//逆序迭代器reverse_iterator
for(vector<int>::reverse_iterator it = v.rbegin();it != v.rend();it++)
{
cout << *it << " " ;
}
cout << endl;
//vector迭代器是随机访问的迭代器 支持跳跃式访问
vector<int>::iterator itBegin = v.begin();
itBegin = itBegin + 3;
//如果上述写法不报错,这个迭代器是随机访问迭代器
list<int>l;
for(int i = 0;i<10;i++)
{
l.push_back(i);
}
list<int>::iterator lIt = l.begin();
// lIt = lIt + 1; //不支持随机访问
}