STL之vector

来源:互联网 发布:淘宝格子铺登陆网址 编辑:程序博客网 时间:2024/05/18 00:05

vector(向量):

        vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型动态数组,能够增加和压缩数据。

        数组的缺点是分配空间不灵活;链表的缺点是无法通过下标快速找到结点。而向量吸收了这两种数据结构各自的优点,综合性能较高。向量的分配空间是会随着数据的量的变化而变化的,如果空间不够,那么向量的空间会自动增长。类似于数组,也可以通过下标来访问向量中的数据元素,快速找到数据。(数组的效率比vector高,而vector用起来比较方便)

        vector的扩充机制:按照容器现在容量的一倍进行增长。vector容器分配的是一块连续的内存空间,每次容器的增长,并不是在原有连续的内存空间后再进行简单的叠加,而是重新申请一块更大的新内存,并把现有容器中的元素逐个复制过去,然后销毁旧的内存。这时原有指向旧内存空间的迭代器已经失效,所以当操作容器时,迭代器要及时更新。


使用时要包含vector头文件(#include<vector>),要命名限定std::vector。

 

vector<int> a(n);         //按需创建

vector<int> b(10, 1);      //10个元素赋全1,灵活的初始化

vector<int> c(b);         //整体拷贝创建

vector<int> f(t, t+5);      //异类拷贝创建

 

        vector是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。和string对象一样,标准库负责管理存储元素的相关内存。我们把vector称为容器,是因为它可以包含其他对象。一个容器中的所有对象都必须是同一种类型的。

        vector是一个类模板(class template。模板允许程序员编写单个类或函数定义,这个类和函数定义可用于不同的数据类型上。因此,可以定义保存string对象的vector,或保存int值的vector,又或是保存自定义类型对象(如Sales_item对象)的vector。

        声明从类模板产生的某种类型的对象,需要提供附加信息,信息的种类取决于模板。以vector为例,必须说明vector保存何种对象的类型,通过将类型放在类模板名称后面的尖括号中来指定类型:

vector<int> ivec;   

vector<Sales_item> Sales_vec;

和其他变量定义一样,定义vector对象要指定类型和一个变量的列表。上面的第一个定义,类型是vector<int>,该类型即是含有若干个int类型对象的vector,变量名为ivec。

第二个定义的变量名是Sales_vec,它所保存的元素是Sales_item类型的对象。

vector不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。vector类型的每一种都指定了其保存元素的类型。因此,vector<int>和vector <string>都是数据类型。

 

 

vector对象的定义和初始化:

 

vector<int>  v1;

vector保存类型为int的对象,默认构造函数v1为空

 

vector<int> v2(v1);

v2是v1的一个副本。

 

vector<int> v3(n, i);

v3包含n个值为i的元素。

 

vector<int> v4(n);

v4是有初始化值0的n个副本。

 

1. 创建确定个数的元素

若要创建非空的vector对象,必须给出初始化元素的值。当把一个vector对象复制到另一个vector对象时,新复制的vector中每一个元素都初始化为原vector中相应元素的副本。但这两个vector对象必须保存同一种元素类型:

vector<int> ivec1;

vector<int> ivec2(ivec1);   // ok

vector<string> svec(ivec1); // error

 

可以用元素个数和元素值对vector对象进行初始化。构造函数用元素个数来决定vector对象保存元素的个数,元素值指定每个元素的初始值:

vector<int> ivec4(10, -1);     // 10个元素, 每个都被初始化为 -1

vector<string> svec(10,"hi!"); // 10个string,每个都被初始化为 "hi!"

 

关键概念:vector对象动态增长                                                       

vector对象(以及其他标准库容器对象)的重要属性就在于可以在运行时高效地添加元素。虽然可以对给定元素个数的vector对象预先分配内存,但更有效的方法是先初始化一个空的vector对象,然后再动态地增加元素。

 

 

2. 值初始化

如果没有给出元素的初始化式,那么标准库将提供一个值初始化的(value initialized)元素初始化式。这个由库生成的初始值用于初始化容器中的每个元素。而元素初始化式的值取决于存储在vector中元素的数据类型。

如果vector保存内置类型(如int类型)的元素,那么标准库将用0值创建元素初始化值:

vector<int> ivec(10); // 10个元素, 每个都被初始化为 0

如果向量保存类类型(如string)的元素,标准库将用该类型的默认构造函数创建元素初始值:

vector<string> svec(10); // 10个元素, 每个都被初始化为空的string

                                                       

3. vector的操作


v[n]

返回v中位置为n的元素。

  

v.size()

返回v中元素的个数

 

v1=v2

把v1的元素替换为v2中元素的副本。

 

v1==v2

如果v1与v2相等,则返回true。

 

v.empty()

如果v为空,则返回true,否则返回false。

  

v.push_back(t)

在v的末尾增加一个值为t的元素

 

v. pop_back()

删除最后一个元素(不改变空间大小)


v.clear()

删除v中所有的元素


!=, <, <=, >, >=

保持这些操作符惯有的含义。

 

向vector添加元素

push_back()操作接受一个元素值,并将它作为一个新的元素添加到vector对象的后面,也就是"插入(push)"到vector对象的"后面(back)":

 

string word;

vector<string> svec;       // empty vector

while(cin>>word)

     svec.push_back(word);  // appendword to text

该循环从标准输入读取一系列string对象,逐一追加到vector对象的后面。首先定义一个空的vector对象svec。每循环一次就添加一个新元素到vector对象,并将从输入读取的word值赋予该元素。当循环结束时,svec就包含了所有读入的元素。

 


vector的下标操作

vector中的对象是没有命名的,可以按vector中对象的位置来访问它们。通常使用下标操作符来获取元素。vector的下标操作类似于string类型的下标操作。

vector的下标操作符接受一个值,并返回vector中该对应位置的元素。vector元素的位置从0开始。下例使用for循环把vector中的每个元素值都重置为0:

 

for(vector<int>::size_typeix=0;ix!=ivec.size();++ix)

      ivec[ix]=0;

 

和string类型的下标操作符一样,vector下标操作的结果为左值,因此可以像循环体中所做的那样实现写入。另外,和string对象的下标操作类似,这里用size_type类型作为vector下标的类型。

 

在上例中,即使ivec为空,for循环也会正确执行。ivec为空则调用size返回0,并且for中的测试比较ix和0。第一次循环时,由于ix本身就是0,则条件测试失败,for循环体一次也不执行。

C++程序员习惯于优先选用!=而不是<来编写循环判断条件。

 

 

下标操作不添加元素

初学C++的程序员可能会认为vector的下标操作可以添加元素,其实不然:

vector<int> ivec;   // empty vector

for (vector<int>::size_typeix=0;ix!=10;++ix)

      ivec[ix]=ix; // disaster: ivec has no elements

 

 

上述程序试图在ivec中插入10个新元素,元素值依次为0到9的整数。但是,这里ivec是空的vector对象,而且下标只能用于获取已存在的元素

这个循环的正确写法应该是:

for(vector<int>::size_typeix=0;ix!=10;++ix)

   ivec.push_back(ix);  // ok: addsnew element with value ix

 

必须是已存在的元素才能用下标操作符进行索引。通过下标操作进行赋值时,不会添加任何元素。

 警告:仅能对确知已存在的元素进行下标操作                                          

 

 

对于下标操作符([]操作符)的使用有一点非常重要,就是仅能提取确实已存在的元素,例如:

vector<int> ivec;      // empty vector

cout<<ivec[0];        // Error: ivec has no elements!

vector<int> ivec2(10); // vector with10 elements

cout<<ivec[10];      // Error: ivec has elements 0...9

 

本警告适用于任何使用下标操作的时候,如string类型的下标操作,以及内置数组的下标操作。

 

不幸的是,试图对不存在的元素进行下标操作是程序设计过程中经常会犯的严重错误。所谓的“缓冲区溢出”错误就是对不存在的元素进行下标操作的结果。这样的缺陷往往导致PC机和其他应用中最常见的安全问题。

0 0