C++ Primer Plus中将vector形容为数组的替代者,因此,vector的底层类似于数组,是一种随机存取的数据结构,顺序线性表。

我们完全可以将vector当作数组来理解,而不同的时,vector通过范型的方式,使存入vector中的数据远不止int、char等基本数据。

除了基本的数据结构,我们可以在其中存入结构体、类等对象。

与数组更大的不同在于,数组必须在声明阶段规定其大小,而vector可以在存入的过程中动态扩展其大小,因此vector的容量分为capacity和size两种,这两种的区别将在后面进行介绍。

在使用vector之前需要导入头文件

#include<vector>

使用时需要命名空间std,因此有两种使用方法

1:

using namespace std;
vector<int> a;

2:

std:vector<int> a;

在我们学习STL中的类的之前首先要学习的就是其构造方法。

C++ STL学习:容器vector\C++ STL学习:容器vector

而vector常用的构造方法有如下几种:

//
//  main.cpp
//  vectorStudy
//
//  Created by 王一帆 on 2018/9/30.
//  Copyright © 2018 王一帆. All rights reserved.
//

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class book
{
private:
    int isBook;
    string bookName;
public:
    book(int ib,string bn):isBook(ib),bookName(bn){};
    int getIsBook()
    {
        return isBook;
    }
    string getBookName()
    {
        return bookName;
    }
};
int main()
{
    vector<int> a=vector<int>(5);                       //定义一个容量为5的vector
    vector<int> b=vector<int>(5,1);                     //定义一个容量为5的vector并初始化为1
    vector<int> c=vector<int>(a.begin(), a.end());      //使用a的迭代器构造c
    vector<int> d=vector<int>({1,2,3,4,5});             //使用列表形式定义一个vector
    vector<book> e=vector<book>({book(1,"History"),book(2,"Math"),book(3,"Biology")});
                                                        //使用列表形式构造一个容纳类的vector
    return 0;
}

vector的初始化方式多样,还有其它通过内存分配方式来构造的构造方法,现在只介绍如上几种。

vector的API:

1.assign:(初始化)

 /*void*/  a.assign(<#size_type __n#>, <#const_reference __u#>);
 /*void*/ a.assign(<#initializer_list<value_type> __il#>);

第一种初始化方式和构造方法类似,size_type n表示将存入对象的长度,而const_reference_ u表示一个常引用类型,即存入对象的引用。而initializer_list<value_type> _il则是列表形式,所以用法很容易。二者返回值都为空。

      a.assign(5, 1);
      a.assign({1,2,3,4,5});

2.at:(按位取值)

 /*reference*/ a.at(<#size_type __n#>)

当然,我们也可以像数组一样使用a[i]的方式取在第i位的值,但是这种取值方式是更安全的,因为它在取值之前会先判断所取的位是否溢出,因此这是一种更保险的方式,尽管其在存取效率上略逊于a[i]这种方式,但是在编程过程中,数组溢出所能造成的影响远比这些微不足道的效率差更大,所以推荐使用a.at(i)这种方式。其返回值为第i位的引用。

3.back:(末位)/front:(首位)

/*reference*/ a.back();

a中有内容时返回最后一位/第一位的引用,无内容时则会报错。

4.begin/end:(begin迭代器和end迭代器):

 迭代器共五种:输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器。具体差别将另开贴谈,我们当前只需知道vector所使用的是随机访问迭代器,因此,我们可以通过a.begin()+n这种方式访问任意一点的迭代器。

 除此之外,需要注意的是STL所使用的是左闭右开的结构,所以a.begin()所对应的是a的第一位的迭代器,而a.end()所对应的是a的最后一位的下一个迭代器。

因此,我们获取了遍历vector的另外一种方式:

for (auto it=a.begin(); it!=a.end(); it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;
    for (auto i=b.begin(); i!=b.end(); i++)
    {
        cout<<i->getIsBook()<<" ";
    }

5.clear:(清空)

清空vector的内容以及所获取的内存空间。返回值,void。

6.data:

返回指向vector中第一个数据的指针或空vector之后的位置

/*value_type* */ a.data()

返回的是value_type*,因此,返回类型应为存入对象的指针。

7.erase:(删除)

/*iterator*/ a.erase(<#const_iterator __position#>)
/*iterator*/ a.erase(<#const_iterator __first#>, <#const_iterator __last#>)

删除方法是按照迭代器的位置进行删除,第一种方法中,参数const_iterator _position表示的是一个const型的迭代器,所以假设我们删除第4个节点可以使用这样的方式:

a.erase(a.begin()+3);

同理,删除最后一个节点需要使用如下方式:

a.erase(a.end()-1);

第二种很显然是删除一段:

a.erase(a.begin()+2, a.begin()+4);

这样便删除了第3、4个节点。之所以没有删除第五个节点,是因为STL的左闭右开机制。

需要注意的是,erase是有返回值的,它的返回值是一个迭代器,表示的是被删除段后面的第一个节点的迭代器,所以我们同样可以使用上文中访问迭代器的方式访问被删除段的后一个节点。要注意,erase的返回值在实际应用中很可能有很大的作用。

另外,删除操作并不能改变vector的capacity,也就是为其开辟的内存空间,只能改变size,即存入的容量。

8.insert:(插入)

    /*iterator*/ a.insert(<#const_iterator __position#>, <#const_reference __x#>);
    /*iterator*/ a.insert(<#const_iterator __position#>, <#value_type &&__x#>);
    /*iterator*/ a.insert(<#const_iterator __position#>,<#size_type __n#>, <#const_reference __x#>);
    /*iterator*/ a.insert(<#const_iterator __position#>, <#initializer_list<value_type> __il#>);
    /*typename enable_if<value,iterator>::type*/ a.insert(<#const_iterator __position#>, <#_InputIterator __first#>, <#_InputIterator __last#>);
    /*typename enable_if<value,iterator>::type*/ a.insert(<#const_iterator __position#>, <#_ForwardIterator __first#>, <#_ForwardIterator __last#>);

与删除类似,你可以在某位置(迭代器位置)之前插入引用、值、值和个数、列表,输入迭代器,前向迭代器。

你可以向insert传另一个同类型迭代器想插入段的头和尾来插入一段内容。

与delete类似的是,insert也是有返回值的,其返回值是插入段的第一个节点所对应的迭代器。

9.pop_back(弹出):

弹出末位,返回void。

10.push_back(压入):

    /*void*/ a.push_back(<#const_reference __x#>);
    /*void*/ a.push_back(<#value_type &&__x#>);

和栈类似,将内容压到vector的末尾。可以传入引用或值。

11.reverse\resize\shrink_to_fit(重新分配内存空间):

    /*void*/ a.reserve(<#size_type __n#>);
    /*void*/ a.reserve(<#size_type __n#>);
    /*void*/ a.resize(<#size_type __sz#>, <#const_reference __x#>);
    /*void*/  a.shrink_to_fit()

可以将内存空间重新分配,分配到最低容量的大小。区别在于reverse\resize可自定义,而后者自动使capacity降为size。

12.swap(交换):

 /*void*/ a.swap(<#vector<int, allocator<int> > &#>) 

与另一个vector进行交换,参数 allocator<int> > &表示的是内存空间的分配方式。

13.empty(判断空):

/*bool*/ a.empty()

14.size/capacity(容量\内存空间):

    /*size_type*/ a.size();
    /*size_type*/ a.capacity();

与数组不同的是,vector可以在加入对象的同时为其动态分配内存空间,而当插入过程中capacity会出现比size大的情况。比如插入8个数据时,本人编译器测出size为8,而capacity为16。

 

相关文章: