博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转载) STL Vector容器
阅读量:6260 次
发布时间:2019-06-22

本文共 18435 字,大约阅读时间需要 61 分钟。

 
 

vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组。像数组一样,vector类也用从0开始的下标表示元素的位置;但和数组不同的是,当vector对象创建后,数组的元素个数会随着vector对象元素个数的增大和缩小而自动变化。

    vector类常用的函数如下所示:

    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)中元素设置成当前向量元素

示例:

  1.初始化示例

[cpp]
  1. #include "stdafx.h" 
  2. #include<iostream> 
  3. #include<vector> 
  4.  
  5. usingnamespace std; 
  6.  
  7. class
  8.     //空类 
  9. }; 
  10. int _tmain(int argc, _TCHAR* argv[]) 
  11.      
  12.     //int型vector 
  13.     vector<int> vecInt; 
  14.  
  15.     //float型vector 
  16.     vector<float> vecFloat; 
  17.  
  18.     //自定义类型,保存类A的vector 
  19.     vector<A> vecA; 
  20.  
  21.     //自定义类型,保存指向类A的指针的vector 
  22.     vector<A*> vecPointA; 
  23.  
  24.     return 0; 
#include "stdafx.h"#include
#include
using namespace std;class A{ //空类};int _tmain(int argc, _TCHAR* argv[]){ //int型vector vector
vecInt; //float型vector vector
vecFloat; //自定义类型,保存类A的vector vector
vecA; //自定义类型,保存指向类A的指针的vector vector
vecPointA; return 0;}
[cpp]
  1. // vectorsample.cpp : 定义控制台应用程序的入口点。 
  2. // 
  3.  
  4. #include "stdafx.h" 
  5. #include<iostream> 
  6. #include<vector> 
  7.  
  8. usingnamespace std; 
  9.  
  10. class
  11.     //空类 
  12. }; 
  13. int _tmain(int argc, _TCHAR* argv[]) 
  14.      
  15.     //int型vector,包含3个元素 
  16.     vector<int> vecIntA(3); 
  17.      
  18.     //int型vector,包含3个元素且每个元素都是9 
  19.     vector<int> vecIntB(3,9); 
  20.  
  21.     //复制vecIntB到vecIntC 
  22.     vector<int> vecIntC(vecIntB); 
  23.      
  24.     int iArray[]={2,4,6}; 
  25.     //创建vecIntD 
  26.     vector<int> vecIntD(iArray,iArray+3); 
  27.  
  28.     //打印vectorA,此处也可以用下面注释内的代码来输出vector中的数据 
  29.     /*for(int i=0;i<vecIntA.size();i++)
  30.     {
  31.         cout<<vecIntA[i]<<"     ";
  32.     }*/ 
  33.  
  34.     cout<<"vecIntA:"<<endl; 
  35.     for(vector<int>::iterator it = vecIntA.begin();it!=vecIntA.end();it++) 
  36.     { 
  37.         cout<<*it<<"     "
  38.     } 
  39.     cout<<endl; 
  40.  
  41.     //打印vecIntB 
  42.     cout<<"VecIntB:"<<endl; 
  43.     for(vector<int>::iterator it = vecIntB.begin() ;it!=vecIntB.end();it++) 
  44.     { 
  45.         cout<<*it<<"     "
  46.     } 
  47.     cout<<endl; 
  48.  
  49.     //打印vecIntC 
  50.     cout<<"VecIntB:"<<endl; 
  51.     for(vector<int>::iterator it = vecIntC.begin() ;it!=vecIntC.end();it++) 
  52.     { 
  53.         cout<<*it<<"     "
  54.     } 
  55.     cout<<endl; 
  56.  
  57.     //打印vecIntD 
  58.     cout<<"vecIntD:"<<endl; 
  59.     for(vector<int>::iterator it = vecIntD.begin() ;it!=vecIntD.end();it++) 
  60.     { 
  61.         cout<<*it<<"     "
  62.     } 
  63.     cout<<endl; 
  64.     return 0; 
// vectorsample.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include
#include
using namespace std;class A{ //空类};int _tmain(int argc, _TCHAR* argv[]){ //int型vector,包含3个元素 vector
vecIntA(3); //int型vector,包含3个元素且每个元素都是9 vector
vecIntB(3,9); //复制vecIntB到vecIntC vector
vecIntC(vecIntB); int iArray[]={2,4,6}; //创建vecIntD vector
vecIntD(iArray,iArray+3); //打印vectorA,此处也可以用下面注释内的代码来输出vector中的数据 /*for(int i=0;i
::iterator it = vecIntA.begin();it!=vecIntA.end();it++) { cout<<*it<<" "; } cout<
::iterator it = vecIntB.begin() ;it!=vecIntB.end();it++) { cout<<*it<<" "; } cout<
::iterator it = vecIntC.begin() ;it!=vecIntC.end();it++) { cout<<*it<<" "; } cout<
::iterator it = vecIntD.begin() ;it!=vecIntD.end();it++) { cout<<*it<<" "; } cout<
程序的运行结果如下:

 

上面的代码用了4种方法建立vector并对其初始化

  2.增加及获得元素示例:

[cpp]
  1. // vectorsample.cpp : 定义控制台应用程序的入口点。 
  2. // 
  3.  
  4. #include "stdafx.h" 
  5. #include<iostream> 
  6. #include<vector> 
  7.  
  8. usingnamespace std; 
  9.  
  10.  
  11. int _tmain(int argc, _TCHAR* argv[]) 
  12.      
  13.     //int型vector,包含3个元素 
  14.     vector<int> vecIntA; 
  15.  
  16.     //插入1 2 3 
  17.     vecIntA.push_back(1); 
  18.     vecIntA.push_back(2); 
  19.     vecIntA.push_back(3); 
  20.      
  21.     int nSize = vecIntA.size(); 
  22.  
  23.     cout<<"vecIntA:"<<endl; 
  24.  
  25.     //打印vectorA,方法一: 
  26.     for(int i=0;i<nSize;i++) 
  27.     { 
  28.         cout<<vecIntA[i]<<"     "
  29.     } 
  30.     cout<<endl; 
  31.  
  32.     //打印vectorA,方法二:     
  33.     for(int i=0;i<nSize;i++) 
  34.     { 
  35.         cout<<vecIntA.at(i)<<"     "
  36.     } 
  37.     cout<<endl; 
  38.  
  39.     //打印vectorA,方法三: 
  40.     for(vector<int>::iterator it = vecIntA.begin();it!=vecIntA.end();it++) 
  41.     { 
  42.         cout<<*it<<"     "
  43.     } 
  44.     cout<<endl; 
  45.      
  46.     return 0; 
// vectorsample.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include
#include
using namespace std;int _tmain(int argc, _TCHAR* argv[]){ //int型vector,包含3个元素 vector
vecIntA; //插入1 2 3 vecIntA.push_back(1); vecIntA.push_back(2); vecIntA.push_back(3); int nSize = vecIntA.size(); cout<<"vecIntA:"<
::iterator it = vecIntA.begin();it!=vecIntA.end();it++) { cout<<*it<<" "; } cout<
上述代码对一个整形向量类进行操作,先定义一个整形元素向量类,然后插入3个值,并用3种不同的方法输出,程序运行结果如下:
 
[cpp]
  1. // vectorsample.cpp : 定义控制台应用程序的入口点。 
  2. // 
  3.  
  4. #include "stdafx.h" 
  5. #include<iostream> 
  6. #include<vector> 
  7.  
  8. usingnamespace std; 
  9.  
  10. class
  11. public
  12.     int n; 
  13. public
  14.     A(int n) 
  15.     { 
  16.         this->n = n; 
  17.     } 
  18. }; 
  19.  
  20. int _tmain(int argc, _TCHAR* argv[]) 
  21.      
  22.     //int型vector,包含3个元素 
  23.     vector<A> vecClassA; 
  24.  
  25.     A a1(1); 
  26.     A a2(2); 
  27.     A a3(3); 
  28.  
  29.     //插入1 2 3 
  30.     vecClassA.push_back(a1); 
  31.     vecClassA.push_back(a2); 
  32.     vecClassA.push_back(a3); 
  33.      
  34.      
  35.     int nSize = vecClassA.size(); 
  36.  
  37.     cout<<"vecClassA:"<<endl; 
  38.  
  39.     //打印vecClassA,方法一: 
  40.     for(int i=0;i<nSize;i++) 
  41.     { 
  42.         cout<<vecClassA[i].n<<"     "
  43.     } 
  44.     cout<<endl; 
  45.  
  46.     //打印vecClassA,方法二:   
  47.     for(int i=0;i<nSize;i++) 
  48.     { 
  49.         cout<<vecClassA.at(i).n<<"     "
  50.     } 
  51.     cout<<endl; 
  52.  
  53.     //打印vecClassA,方法三: 
  54.     for(vector<A>::iterator it = vecClassA.begin();it!=vecClassA.end();it++) 
  55.     { 
  56.         cout<<(*it).n<<"     "
  57.     } 
  58.     cout<<endl; 
  59.      
  60.     return 0; 
// vectorsample.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include
#include
using namespace std;class A{public: int n;public: A(int n) { this->n = n; }};int _tmain(int argc, _TCHAR* argv[]){ //int型vector,包含3个元素 vector
vecClassA; A a1(1); A a2(2); A a3(3); //插入1 2 3 vecClassA.push_back(a1); vecClassA.push_back(a2); vecClassA.push_back(a3); int nSize = vecClassA.size(); cout<<"vecClassA:"<
::iterator it = vecClassA.begin();it!=vecClassA.end();it++) { cout<<(*it).n<<" "; } cout<
上述代码通过定义元素为类的向量,通过插入3个初始化的类,并通过3种方法输出,运行结果如下:

 

 

[cpp]
  1. // vectorsample.cpp : 定义控制台应用程序的入口点。 
  2. // 
  3.  
  4. #include "stdafx.h" 
  5. #include<iostream> 
  6. #include<vector> 
  7.  
  8. usingnamespace std; 
  9.  
  10. class
  11. public
  12.     int n; 
  13. public
  14.     A(int n) 
  15.     { 
  16.         this->n = n; 
  17.     } 
  18. }; 
  19.  
  20. int _tmain(int argc, _TCHAR* argv[]) 
  21.      
  22.     //int型vector,包含3个元素 
  23.     vector<A*> vecClassA; 
  24.  
  25.     A *a1 = new A(1); 
  26.     A *a2 = new A(2); 
  27.     A *a3 = new A(3); 
  28.  
  29.     //插入1 2 3 
  30.     vecClassA.push_back(a1); 
  31.     vecClassA.push_back(a2); 
  32.     vecClassA.push_back(a3); 
  33.      
  34.      
  35.     int nSize = vecClassA.size(); 
  36.  
  37.     cout<<"vecClassA:"<<endl; 
  38.  
  39.     //打印vecClassA,方法一: 
  40.     for(int i=0;i<nSize;i++) 
  41.     { 
  42.         cout<<vecClassA[i]->n<<"\t"
  43.     } 
  44.     cout<<endl; 
  45.  
  46.     //打印vecClassA,方法二:   
  47.     for(int i=0;i<nSize;i++) 
  48.     { 
  49.         cout<<vecClassA.at(i)->n<<"\t"
  50.     } 
  51.     cout<<endl; 
  52.  
  53.     //打印vecClassA,方法三: 
  54.     for(vector<A*>::iterator it = vecClassA.begin();it!=vecClassA.end();it++) 
  55.     { 
  56.         cout<<(**it).n<<"\t"
  57.     } 
  58.     cout<<endl; 
  59.     delete a1; delete a2;delete a3; 
  60.     return 0; 
// vectorsample.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include
#include
using namespace std;class A{public: int n;public: A(int n) { this->n = n; }};int _tmain(int argc, _TCHAR* argv[]){ //int型vector,包含3个元素 vector
vecClassA; A *a1 = new A(1); A *a2 = new A(2); A *a3 = new A(3); //插入1 2 3 vecClassA.push_back(a1); vecClassA.push_back(a2); vecClassA.push_back(a3); int nSize = vecClassA.size(); cout<<"vecClassA:"<
n<<"\t"; } cout<
n<<"\t"; } cout<
::iterator it = vecClassA.begin();it!=vecClassA.end();it++) { cout<<(**it).n<<"\t"; } cout<
上述代码通过定义元素为类指针的向量,通过插入3个初始化的类指针,并通过3种方法输出指针指向的类,运行结果如下:

 

  3.修改元素示例

修改元素的方法主要有三种:1.通过数组修改,2.通过引用修改,3.通过迭代器修改
[cpp]
  1. // vectorsample.cpp : 定义控制台应用程序的入口点。 
  2. // 
  3.  
  4. #include "stdafx.h" 
  5. #include<iostream> 
  6. #include<vector> 
  7.  
  8. usingnamespace std; 
  9.  
  10.  
  11. int _tmain(int argc, _TCHAR* argv[]) 
  12.      
  13.     //int型vector,包含3个元素 
  14.     vector<int> vecIntA; 
  15.  
  16.     //插入1 2 3 
  17.     vecIntA.push_back(1); 
  18.     vecIntA.push_back(2); 
  19.     vecIntA.push_back(3); 
  20.      
  21.     int nSize = vecIntA.size(); 
  22.  
  23.     //通过引用修改vector 
  24.     cout<<"通过数组修改,第二个元素为8:"<<endl; 
  25.     vecIntA[1]=8; 
  26.  
  27.     cout<<"vecIntA:"<<endl; 
  28.     //打印vectorA 
  29.     for(vector<int>::iterator it = vecIntA.begin();it!=vecIntA.end();it++) 
  30.     { 
  31.         cout<<*it<<"     "
  32.     } 
  33.     cout<<endl; 
  34.      
  35.     //通过引用修改vector 
  36.     cout<<"通过引用修改,第二个元素为18:"<<endl; 
  37.     int &m = vecIntA.at(1); 
  38.     m=18; 
  39.  
  40.     cout<<"vecIntA:"<<endl; 
  41.     //打印vectorA 
  42.     for(vector<int>::iterator it = vecIntA.begin();it!=vecIntA.end();it++) 
  43.     { 
  44.         cout<<*it<<"     "
  45.     } 
  46.     cout<<endl; 
  47.  
  48.     //通过迭代器修改vector 
  49.     cout<<"通过迭代器修改,第二个元素为28"<<endl; 
  50.     vector<int>::iterator itr = vecIntA.begin()+1; 
  51.     *itr = 28; 
  52.  
  53.     cout<<"vecIntA:"<<endl; 
  54.     //打印vectorA 
  55.     for(vector<int>::iterator it = vecIntA.begin();it!=vecIntA.end();it++) 
  56.     { 
  57.         cout<<*it<<"     "
  58.     } 
  59.     cout<<endl; 
  60.  
  61.     return 0; 
// vectorsample.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include
#include
using namespace std;int _tmain(int argc, _TCHAR* argv[]){ //int型vector,包含3个元素 vector
vecIntA; //插入1 2 3 vecIntA.push_back(1); vecIntA.push_back(2); vecIntA.push_back(3); int nSize = vecIntA.size(); //通过引用修改vector cout<<"通过数组修改,第二个元素为8:"<
::iterator it = vecIntA.begin();it!=vecIntA.end();it++) { cout<<*it<<" "; } cout<
::iterator it = vecIntA.begin();it!=vecIntA.end();it++) { cout<<*it<<" "; } cout<
::iterator itr = vecIntA.begin()+1; *itr = 28; cout<<"vecIntA:"<
::iterator it = vecIntA.begin();it!=vecIntA.end();it++) { cout<<*it<<" "; } cout<
程序运行结果如下:
 

4.删除向量示例

删除向量主要通过erase和pop_back,示例代码如下
[cpp]
  1. // vectorsample.cpp : 定义控制台应用程序的入口点。 
  2. // 
  3.  
  4. #include "stdafx.h" 
  5. #include<iostream> 
  6. #include<vector> 
  7.  
  8. usingnamespace std; 
  9.  
  10.  
  11. int _tmain(int argc, _TCHAR* argv[]) 
  12.      
  13.     //int型vector,包含3个元素 
  14.     vector<int> vecIntA; 
  15.  
  16.     //循环插入1 到10 
  17.     for(int i=1;i<=10;i++) 
  18.     { 
  19.         vecIntA.push_back(i); 
  20.     } 
  21.      
  22.     vecIntA.erase(vecIntA.begin()+4); 
  23.          
  24.     cout<<"删除第5个元素后的向量vecIntA:"<<endl; 
  25.     //打印vectorA 
  26.     for(vector<int>::iterator it = vecIntA.begin();it!=vecIntA.end();it++) 
  27.     { 
  28.         cout<<*it<<"\t"
  29.     } 
  30.     cout<<endl; 
  31.  
  32.     //删除第2-5个元素 
  33.     vecIntA.erase(vecIntA.begin()+1,vecIntA.begin()+5); 
  34.  
  35.     cout<<"删除第2-5个元素后的vecIntA:"<<endl; 
  36.     //打印vectorA 
  37.     for(vector<int>::iterator it = vecIntA.begin();it!=vecIntA.end();it++) 
  38.     { 
  39.         cout<<*it<<"\t"
  40.     } 
  41.     cout<<endl; 
  42.  
  43.     //删除最后一个元素 
  44.     vecIntA.pop_back(); 
  45.  
  46.     cout<<"删除最后一个元素后的vecIntA:"<<endl; 
  47.     //打印vectorA 
  48.     for(vector<int>::iterator it = vecIntA.begin();it!=vecIntA.end();it++) 
  49.     { 
  50.         cout<<*it<<"\t"
  51.     } 
  52.     cout<<endl; 
  53.  
  54.     return 0; 
// vectorsample.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include
#include
using namespace std;int _tmain(int argc, _TCHAR* argv[]){ //int型vector,包含3个元素 vector
vecIntA; //循环插入1 到10 for(int i=1;i<=10;i++) { vecIntA.push_back(i); } vecIntA.erase(vecIntA.begin()+4); cout<<"删除第5个元素后的向量vecIntA:"<
::iterator it = vecIntA.begin();it!=vecIntA.end();it++) { cout<<*it<<"\t"; } cout<
::iterator it = vecIntA.begin();it!=vecIntA.end();it++) { cout<<*it<<"\t"; } cout<
::iterator it = vecIntA.begin();it!=vecIntA.end();it++) { cout<<*it<<"\t"; } cout<
程序运行结果如下:
 
 
 
 

3.进一步理解vector,如下图所示:

   
当执行代码vector<int> v(2,5)时,在内存里建立了2个整形元素空间,值是5.当增加一个元素时,原有的空间由2个编程4个整形元素空间,并把元素1放入第3个整形空间,第4个空间作为预留空间。当增加元素2时,直接把值2放入第4个空间。当增加元素3时,由于原有向量中没有预留空间,则内存空间由4个变为8个整形空间,并把值放入第5个内存空间。
   总之,扩大新元素时,如果超过当前的容量,则容量会自动扩充2倍,如果2倍容量仍不足,则继续扩大2倍。本图是直接在原空间基础上画的新增空间,其实要复杂的多,包括重新配置、元素移动、释放原始空间的过程。因此对vector容器而言,当增加新的元素时,有可能很快完成(直接存在预留空间中),有可能稍慢(扩容后再放新元素);对修改元素值而言是较快的;对删除元素来说,弱删除尾部元素较快,非尾部元素稍慢,因为牵涉到删除后的元素移动。
 
 
 
附一篇不错的文章:vector的增长机制
 
引言:
 
 
假设我们希望从一个文件中将一串类型为double的值读进一个数据结构中,从而允许我们高效地访问这些值,通常的方法如下:  
vector<double> values; double x; while (cin >> x)    values.push_back(x); 
 
当循环结束时,values会容纳有所有的值,我们将可以通过values高效地访问任何值。  
 
在直觉上,标准库vector类就像一个内建数组:我们可以认为它在单块连续的内存中容纳其元素。实际上,尽管C++标准没有明确要求vector的元素要占用连续的内存,然而标准委员会在2000年10月份的会议上裁定此项要求的遗漏归因于工作上的疏忽,并且投票表决将其作为技术勘误的一部分而包 含进来。这个迟到的要求谈不上是多大的痛苦,因为每一个现有的vector实现本来就是以这种方式工作的。
 
如果一个vector的元素位于连续的内存中,我们就很容易明白它是如何高效地访问个体元素的 —只要使用与内建数组相同的机制就可以了。不过,要弄明白一个vector实现是如何处理高效增长的问题就不是这么简单了,因为这种增长将不可避免地涉及到 将元素从一块内存区域拷贝到另外一块内存区域。尽管现代处理器通常特别擅长于将一块连续的数据从内存的一个地方拷贝到另一个地方,然而这样的拷贝并非是免 费的午餐。因此,思考一个标准库实现可能是如何处理vector的增长而又不消耗过量的时间或空间,很有意义。
 
本文的余下部分将讨论一个用于管理vector增长的简单而高效的策略。
 
大小和容量: 
 
要想搞清楚vector类的工作机制,首先要清楚它并不仅仅是一块内存。相反,每一个vector都关联有两个“尺寸”:一个称为 大小(size),表示vector容纳的元素的数量;另一个称为容量(capacity),表示可被用来存储元素的内存总量。比方说,假如v是一个vector,那么v.size()和v.capacity()则分别返回v的 大小和容量。你可以想象一个vector看起来如下:   
 
当然了,在vector尾部留有额外的内存的用意在于,当使用push_back向vector追加元素时无需分配更多的内存。如果邻接于vector尾部的内存当时恰好未被占用,那么vector的增长只要将那块内存合并过来即可。然而这样的好运气极其罕见,大多数情况下需要分配新的内 存,然后将vector现有的元素拷贝到那块内存中,然后销毁原来的元素,最后归还元素先前占用的内存。在vector中留有额外的内存的好处在于,这样 的重新分配(代价可能很昂贵)不会每当试图向vector追加一个元素时都发生。  
 
重新分配内存的代价有多高昂?它涉及如下四个步骤:
 
为需要的新容量分配足够的内存;
将元素从原来的内存拷贝到新内存中;
销毁原来的内存中的元素;
归还原来的内存。   
 
如果元素的数目为n,那么我们知道步骤(2)和(3)都要占用O(n)的时间,除非分配或归还内存的代价的增长超过O(n),否则这两步将在全部运 行时间中占居支配地位。因此我们可以得出结论:无论用于重新分配的容量(capacity)是多少,重新分配一个 大小(size)为n的vector需要占用O(n)的时间。   
 
这个结论暗示了一种折衷权衡。假如在重新分配时请求大量的额外内存,那么在相当长的时间内将无需再次进行重新分配,因此总体重新分配操作消耗的时间 相对较少,这种策略的代价在于将会浪费大量的空间。另一方面,我们可以只请求一点点额外的内存,这么做将会节约空间,但后继的重新分配操作将会耗费时间。 换句话说,我们面临一个经典的抉择:拿时间换空间,或者相反。
 
重新分配策略:   
 
 
作为一个极端的例子,假定每当填充vector一次我们就将其容量增加1个单位,这种策略耗费尽可能少的内存空间,但每当追加一个元素时都要重新分 配整个vector。我们说过,重新分配一个具有n个元素的vector占用O(n)的时间,因此,如果我们从一个空vector开始并将其增长到k个元 素,那么占用的总时间将会是O(1+2+...+k)或者O(k2),这太可怕了!有没有更好的办法呢?  
 
比方说,假如不是以步幅1来增长vector的容量,而是以一个常量C的步幅来增长它将会如何?很明显这个策略将会减少重新分配的次数(基于因子C),所以这当然是一种改进,但这个改进到底有多大呢?
 
理解这个改进的方式之一是要认识到此一新策略将针对每C个元素块进行一次重新分配。假设我们为总量为KxC个元素分配K块内存,那么,第一次重新分 配将会拷贝C个元素,第二次将会拷贝2xC个元素,等等。Big-O表示法不考虑常量因子,因此我们可以将所有的C因子分摊开来而获得O(1+2+...+K)或者O(K2)的总时间。换句话说,时间仍然是元素个数的二次方程,不过是带有一个小得多的因子罢了。
 
撇开较小的因子不谈,“二次行为”仍然太糟糕,即使有一个快速的处理器也是如此。实际上,对于快速的处理器来说尤其糟糕,因为快速的处理器通常伴有 大量的内存,而访问具有大量内存的快速处理器的程序员常常试图用尽那些内存(这是迟早的事)。这些程序员往往会发现,如果在运行一个二次算法的话,处理器 的速度于事无补。  
 
我们刚刚证实,一个希望能以小于“二次时间”而分配大型vector的实现是不能使用“每次填充时以常量步幅增长vector容量”的策略的,相 反,被分配的附加内存的数量必须随着vector的增长而增长。这个事实暗示存在一种简单的策略:vector从单个元素开始而后每当重新分配时倍增其容 量,如何?事实证明这种策略允许我们以O(n)的时间构建一个有着n个元素的vector。 
 
为了理解是如何获得这样的效率的,考虑当我们已经完全填满它并打算对其重新分配时的vector的状态:   
 
 
自最近一次重新分配内存以来被追加到vector中的元素有一半从未被拷贝过,而对于那些被拷贝的元素而言,其中一半只被拷贝了一次,其余的一半被拷贝了两次,以此类推。 
 
换句话说,有n/2的元素被拷贝了一次或多次,有n/4的元素被拷贝了两次或多次,等等。因此,拷贝元素的总数目为n/2 + n/4 +...,结果可以近似为n(随着n的增大,这个近似值越发精确)。撇开拷贝动作不谈,有n个元素被追加到了vector中,但操作占用的时间总量仍然是O(n)而不是O(n2)。   
 
讨论:   
 
C++标准并没有规定vector类必须以某种特定的方式管理其内存,它只是要求通过重复调用push_back而创建一个具有n个元素的vector耗费的时间不得超过O(n),我们刚才讨论的策略可能是满足此项要求的最直截了当的一种。
   
 
因为对于这样的操作来说vector具有优秀的时间性能,所以没有什么理由避免使用如下循环:
   
 
vector<double> values; double x; while (cin >> x)   values.push_back(x);   
 
是的,当其增长时,实现将会重新分配vector的元素,但是,如果我们事先能够预测vector最终 大小的话,这个重新分配耗费的时间将不会超过“一个常量因子”可能会占用的时间。
   
 
练习:
  
1.设想我们通过以如下方式编写代码而努力使我们那个小型循环速度更快:
   
while (cin >> x) {   if (values.size() == values.capacity())       values.reserve(values.size() + 1000);   values.push_back(x); }
 
效果将会如何?成员函数reserve进行一次重新分配,从而改变vector的capacity,使其大于或等于其参数。 
 
2.设想不是每次倍增vector的大小,而是增大三倍,在性能上将会产生什么样的影响?特别是,创建一个具有n个元素的vector的运行时间仍然为O(n)吗? 
 
3.设想你知道你的vector最终将拥有多少元素,在这种情况下,在填充元素之前你可以调用reserve来预先分配数量合适的内存。试一试你手 头的vector实现,看看调用reserve与否对你的程序的运行时间有多大的影响。
~~The END~~
 
 

4.综合示例

[cpp]
  1. // vectorsample.cpp : 定义控制台应用程序的入口点。 
  2. // 
  3.  
  4. #include "stdafx.h" 
  5. #include<iostream> 
  6. #include<vector> 
  7. #include<string> 
  8. usingnamespace std; 
  9.  
  10. class Student 
  11. public
  12.     string m_strNO; 
  13.     string m_strName; 
  14.     string m_strSex; 
  15.     string m_strDate; 
  16. public
  17.     Student(string strNO,string strName,string strSex,string strDate) 
  18.     { 
  19.         m_strNO = strNO; 
  20.         m_strName = strName; 
  21.         m_strSex = strSex; 
  22.         m_strDate = strDate; 
  23.     } 
  24.     void Display() 
  25.     { 
  26.         cout<<m_strNO<<"\t"
  27.         cout<<m_strName<<"\t"
  28.         cout<<m_strSex<<"\t"
  29.         cout<<m_strDate<<"\t"
  30.     } 
  31. }; 
  32.  
  33. class StudCollect 
  34.     vector<Student> m_vStud; 
  35. public
  36.     void Add(Student &s) 
  37.     { 
  38.         m_vStud.push_back(s); 
  39.     } 
  40.     Student* Find(string strNO) 
  41.     { 
  42.         bool bFind = false
  43.         int i; 
  44.         for(i = 0;i < m_vStud.size();i++) 
  45.         { 
  46.             Student& s = m_vStud.at(i); 
  47.             if(s.m_strNO == strNO) 
  48.             { 
  49.                 bFind = true
  50.                 break
  51.             } 
  52.         } 
  53.         Student *s = NULL; 
  54.         if(bFind) 
  55.             s = &m_vStud.at(i); 
  56.         return s; 
  57.     } 
  58. }; 
  59.  
  60. int _tmain(int argc, _TCHAR* argv[]) 
  61.     Student s1("1001","zhangsan","boy","1988-10-10");    
  62.     Student s2("1002","lisi","boy","1988-8-25"); 
  63.     Student s3("1003","wangwu","boy","1989-2-14"); 
  64.  
  65.     StudCollect s; 
  66.     s.Add(s1); 
  67.     s.Add(s2); 
  68.     s.Add(s3); 
  69.  
  70.     Student *ps = s.Find("1002"); 
  71.     if(ps) 
  72.         ps->Display(); 
  73.     return 0; 
// vectorsample.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include
#include
#include
using namespace std;class Student{public: string m_strNO; string m_strName; string m_strSex; string m_strDate;public: Student(string strNO,string strName,string strSex,string strDate) { m_strNO = strNO; m_strName = strName; m_strSex = strSex; m_strDate = strDate; } void Display() { cout<
<<"\t"; cout<
<<"\t"; cout<
<<"\t"; cout<
<<"\t"; }};class StudCollect{ vector
m_vStud;public: void Add(Student &s) { m_vStud.push_back(s); } Student* Find(string strNO) { bool bFind = false; int i; for(i = 0;i < m_vStud.size();i++) { Student& s = m_vStud.at(i); if(s.m_strNO == strNO) { bFind = true; break; } } Student *s = NULL; if(bFind) s = &m_vStud.at(i); return s; }};int _tmain(int argc, _TCHAR* argv[]){ Student s1("1001","zhangsan","boy","1988-10-10"); Student s2("1002","lisi","boy","1988-8-25"); Student s3("1003","wangwu","boy","1989-2-14"); StudCollect s; s.Add(s1); s.Add(s2); s.Add(s3); Student *ps = s.Find("1002"); if(ps) ps->Display(); return 0;}
代码运行实例如下:
 

v.capacity()     返回容器中数据个数。

v.size()        返回容器中实际数据的个数。

v.reserve()     保留适当的容量。

v.resize(num)    重新指定队列的长度。

v.max_size()       返回容器中最大数据的数量。


View Code
1 #include 
2 #include
3 4 using namespace std; 5 6 int main() 7 { 8 vector
v1(4,1); 9 vector
::iterator iter;10 cout<<"vector的size的值 : "<
<

输出结果:

小结:vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!这是因为:(1)reserve是为容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用push_back()/insert()函数。(2)resize则是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的。

 

转载于:https://www.cnblogs.com/ztteng/articles/3043679.html

你可能感兴趣的文章
Python与C++引用分析
查看>>
误删一个用户 引起数据不准确问题
查看>>
一场失败的拔河比赛
查看>>
IOS开发工程师欢迎你加入宏略信息
查看>>
java 判断当前时间符合cron时间表达式
查看>>
Telnet协议的实现
查看>>
我的友情链接
查看>>
(一)指南一、初学者指南1、简介2、安装
查看>>
约瑟夫·奈:透视网络空间
查看>>
我的友情链接
查看>>
大数据入门基础:Hadoop简介
查看>>
jdk1.7新特性
查看>>
杭电1029--Ignatius and the Princess IV(哈希)
查看>>
使用CSS3改变文本选中的默认颜色
查看>>
课后作业-阅读任务-阅读提问-3
查看>>
[130_存储业务]002_富士通存储系统Eternus_高级拷贝之对等拷贝(Advanced Copy EC)
查看>>
计算器作业(摘要算法)
查看>>
嵌入式 Linux 学习 之路
查看>>
北大acm1006
查看>>
下载PhantomJS
查看>>