C++ Vecctor容器浅析

    科技2022-07-14  193

    Vector的定义

    向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。vector是对象的集合,其中所有对象的类型都相同。集合中的每个对象都有一个与之对应的索引,索引用于访问的对象。vector是模板而不是类型,由vector生成的类型必须包含vector中元素的类型,比如vector<int>。vector不可以将引用作为其元素,因为引用不是对象。

    定义和初始化vector对象

    和任何类型一样,vector模板模板控制着定义和初始化向量的方法。 Vector<T> v1v1是一个空的vector,潜在的元素是T类型的,执行默认初始化Vector<T> v2(v1)

    v2中包含v1中所有元素的副本

    Vector<T> v2 = v1等效于v2(v1),v2中包含v1中所有元素的副本Vector<T> v3(n,val)v3中包含n个重复的元素,每个元素的数值都是valVector<T> v4(n)v3包含了n个重复地执行值初始化的对象Vector<T> v5{a,b,c.......}v5包含了初始值个数的元素,每个元素被赋予相应的初始数值Vector<T> v5={a,b,c.....}等效于Vector<T> v5{a,b,c.......} 使用方法,先定义一个空的vector,当运行的时候将获取到的元素数值逐一添加。vector之间进行赋值拷贝,需要逐一一个前提,那就是类型必须是一致的。 vector<int> ivec; vector<int> ivec2(ivec); vector<int> ivec3 = ivec; vector<string>ivec4 = ivec;//错误,类型不符合

    列表初始化vector对象 

    使用拷贝初始化时(即使用=),只可以提供一个初始数值使用提供的是一个类内初始值,则可以使用拷贝初始化或者使用花括号的形式进行初始化如果提供的是初始元数值的列表,则只能把初始值都放在圆括号里面进行列表初始化,但是不能放在圆括号里面。例如: vector<string> v1 = {"a","ccc","ddd"}; //正确,列表初始化例如: vector<string> v1 = ("a","ccc","ddd"); //错误,不可以使用圆括号

    创建指定数量的元素

    还可以使用vector对象容纳的元素数量和所有元素的统一初始值来初始化vector对象。vector<int> v1(10,-1);//创建10个int类型的元素,每个元素的数值都被初始化为-1vector<string> v2(10,"hi!");//创建10个string类型的元素,每个元素的数值都被初始化为hi!

    值初始化

    可以只提供vector对象容纳的元素数量,而不提供初始数值。此时库会创建一个值初始化的元素初值,并将其赋值给容器中所有的元素。这个初值由vector对象中的元素类型决定。如果vector的对象元素类型是内置类型的,比如int,则元素初始值会被自动设置为0;如果是string类型的,则元素由类默认初始化。

    限制要求

    1,有些类必须明确的提供初始值,如果vector对象中元素的类型不支持默认初始化,就必须提供初始的元素值2,如果只提供了元素的数量没有提供元素的初始值,只能使用直接初始化。vector<int> v1 = 10;//错误,使用直接初始化

    列表初始值还是元素的数量

    初始化的真实含义依赖于传递初始值的时候使用的是花括号还是圆括号

    vector<int> v1 (10); //v1有10个元素,每个元素的数值都是0 vector<int> v2 {10}; //v2有1个元素,元素的数值是10 vector<int> v3(10,1); //v3有10个元素,每个元素的数值都是1 vector<int> v4{10,1};//v4有2个元素,元素的数值分别是10和1

    向vector中添加元素

    直接初始化常见于三种场景:1,初始值已知且数量较少;2,初始值是另外一个vector对象的副本;3,所有元素的初始值一致使用函数push_back将元素添加到vectro容器的末尾,下面的例子是将100个元素押入容器中 vector<int> vInt; for(int i = 0;i !=100 ;i++){ v2.push_back(i); } 从标准输入中读取单词,将其作为vector对象的元素进行存储 string word; vector<string> text; //空的vector对象 while (cin >> word){ text.push_back(word); }  循环体内部包含了有向vector对象添加元素的语句,则不可以使用范围for循环。

    其他vector操作

    v.empty()如果v不含有任何元素,返回为真;否则返回为假v.size()

    返回元素的个数

    v.push_back(t)向v的末尾添加一个数值为t的元素v[n]返回v中第n个位置上元素的引用v1=v2用v2中的元素拷贝替换v1中的元素v1={a,b,c...}

    用列表中的元素拷贝替换v1中的元素

    v1 == v2 v1和v2相等当且仅当元素数量相同,且对应位置上的元素值都相等v1 != v2 < <= >= >以字典序比较大小 访问vector中的元素和访问string对象中字符的方式差不多,也是通过元素在vector对象上的位置。 例如可以使用范围for语句来处理vector中所有元素。 vector<int> v {1,2,3,4,5,6,7,8,9}; for(auto &i : v){ //对于v中每个元素进行处理,其中i是一个引用 i *= i; } for(auto &i : v){ cout << i << " " << endl; }

    第一个循环把控制变量i定义成引用类型,这样就可以通过i给v的元素赋值

    要使用size_type的时候,需要指定它是由哪种类型定义的。例如:vector<int>::size_type   //正确

    计算Vector内对象的索引

    可以通过下标运算符来获取指定的元素;还可以通过计算得到vector内对象的索引,然后直接获取索引位置上的元素。 计算得到vector内对象的索引,举个例子,对于输入的成绩进行归档,每10分一个档次。计算方式是将其除以10就能得到对应的分数段索引,例如65/10 = 6;42/10 = 4;一旦计算得到了分数段索引,就可以把它作为vector对象的下标,进而可以获取该分数段的计算值并加1。 // 以10分为一个分数段统计成绩的数量,0~9,10~19,...,90~99,100 vector<unsigned> scores(11,0); //11个分数段,全部初始化为0 unsigned grade; while(cin >> grade){ //读取成绩 if(grade <= 100 ){ //只处理有效的成绩 ++scores[grade / 10]; //将对应分数段的计数值加1 } if(grade == 'T'){ //输入字符T,退出程序 break; } } for(auto i : scores){ //输出存储的字段信息 cout << i << " " << endl; }

    不可以使用下标的形式添加元素

    vector<int> ivec;//空的vector对象 for(decltype(ivec.size()) ix = 0; ix != 10; ix++){ ivec[ix] = ix;//严重错误,vector不包含任何的元素 } 正确的方法是通过push_back的方法,将元素逐一押入容器中。vector对象的下标运算符可以用于访问已经存在的元素,但是不可以用于添加元素。 

    容器的特性

    顺序序列

    顺序容器中的元素按照严格的线性顺序排序。可以通过元素在序列中的位置访问对应的元素。

    动态数组

    能够感知内存分配器的(Allocator-aware)

    容器使用一个内存分配器对象来动态地处理它的存储需求

    基本函数实现

    1.构造函数

    vector():创建一个空vectorvector(int nSize):创建一个vector,元素个数为nSizevector(int nSize,const t& t):创建一个vector,元素个数为nSize,且值均为tvector(const vector&):复制构造函数vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中

    2.增加函数

    void push_back(const T& x):向量尾部增加一个元素Xiterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素xiterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素xiterator 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个元素的值为xvoid assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素

    8.补充完善

    push_back 在数组的最后添加一个数据pop_back 去掉数组的最后一个数据at 得到编号位置的数据begin 得到数组头的指针end 得到数组的最后一个单元+1的指针front 得到数组头的引用back 得到数组的最后一个单元的引用max_size 得到vector最大可以是多大capacity 当前vector分配的大小size 当前使用数据的大小resize 改变当前使用数据的大小,如果它比当前使用的大,则填充默认值reserve 改变当前vecotr所分配空间的大小erase 删除指针指向的数据项clear 清空当前的vectorrbegin 将vector反转后的开始指针返回(其实就是原来的end-1)rend 将vector反转构的结束指针返回(其实就是原来的begin-1)empty 判断vector是否为空swap 与另一个vector交换数据

    基本用法

    #include < vector> using namespace std;

    简单的介绍

    Vector<类型>标识符Vector<类型>标识符(最大容量)Vector<类型>标识符(最大容量,初始所有值)Int i[5]={1,2,3,4,5} Vector<类型>vi(I,i+2);//得到i索引值为3以后的值Vector< vector< int> >v; 二维向量//这里最外的<>要有空格。否则在比较旧的编译器下无法通过

    相关知识的引用

    模板

    模板本身不是类或者函数,相反可以把模板看做是编译器生成类或者函数的说明。编译器根据模板创建类或者函数的过程称为实例化,当使用模板的时候,需要指出编译器把类或者函数实例化成为哪种类型。对于类模板来讲,提供一些额外的类来指定将模板实例化成为什么样的类。需要提供的信息是由模板来决定的,即在模板名字的后面跟上一段尖括号,在括号上放上相关的信息。以vector为例,提供的额外信息是vector内所存放对象的类型 vectorr<int> ivec;//ivec保存int类型的对象 vector<Sales_item> Sales_vec;//保存Sales_item类型的对象 vector<vector<string>> file;//该向量的元素是vector对象

    缓冲区溢出

    通过下标访问不存在的元素会导致缓冲区溢出。
    Processed: 0.012, SQL: 8