vector< T>向量容器

头文件:#include<vector>

特点:可以动态调整所占用的内存空间,擅长在尾部插入/删除元素。

创建一个vector
std::vector<int> int_vec;//创建一个int类型的vector容器
std::vector<double> double_vec{0.2,4.2,3.99};//初始化时指定初始值及元素个数
std::vector<char> char_vec(5);//创建具有5个char类型元素的vector容器,默认值为0
std::vector<int> temp(10,2);//创建具有10个int类型元素且默认值为2的vector容器
std::vector<int> temp2(temp);//通过其他的容器来创建自己的vector容器

注意:采用std::vector<int> temp(10,2);创建vecotr容器时,两个参数既可以是常量,也可以是变量。

vector成员函数

下面我们通过实例来简单介绍下vector成员函数的作用:

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

int main()
{
    std::vector<int> int_vec{1,9,8,8,0,3,2,1};
    for (int i = 0; i < int_vec.size(); i++)//利用size()成员函数遍历vector容器
    {//size():返回容器元素个数
        cout<<int_vec[i]<<" ";//像普通数组一样访问容器元素
    }
    cout<<endl;
    
    cout<<"push a 25 at last!"<<endl;
    int_vec.push_back(25);//push_back():在序列的尾部添加一个元素
    //也可以使用emplace_back()成员函数,与push_back作用一样,但前者更快。
    vector<int>::iterator iter;
    for (auto iter = int_vec.begin(); iter != int_vec.end(); iter++)//通过begin()和end()成员函数遍历vector容器
    {//begin():返回指向容器中第一个元素的迭代器
     //end():返回指向容器最后一个元素所在位置后一个位置的迭代器
        cout<<*iter<<" ";
    }
    cout<<endl;
    cout<<"pop 3 elem at last"<<endl;
    for (int i = 0; i < 3; i++)
    {
        cout<<"the elem which is poped is :"<<int_vec.back()<<endl;
        //back():返回最后一个元素的引用
        int_vec.pop_back();
        //pop_back():移出序列尾部的元素
    }
    cout<<"now the vector's size is : "<<int_vec.size()<<endl;
    cout<<"we change the size to nowsize * 2"<<endl;
    int_vec.resize(int_vec.size()*2);//resize():改变实际元素的个数。
    int * ptr = int_vec.data();//data():返回指向容器中第一个元素的指针。
    for (int i = 0; i < int_vec.size(); i=i+2)
    {
        cout<<*(ptr+i)<<" ";
    }
    cout<<endl;
    vector<int> temp{1,1,0};
    int_vec.swap(temp);//swap():交换两个容器的所有元素
    for (int i = 0; i < int_vec.size(); i++)
    {
        cout<<int_vec.at(i)<<" ";//at():使用经过边界检查的索引访问元素。越界会抛出异常哦~
    }
    cout<<endl;
    getchar();
    return 0; 
}

输出:

1 9 8 8 0 3 2 1
push a 25 at last!
1 9 8 8 0 3 2 1 25
pop 3 elem at last
the elem which is poped is :25
the elem which is poped is :1
the elem which is poped is :2
now the vector's size is : 6
we change the size to nowsize * 2
1 8 0 0 0 0
1 1 0

vector<T>的常用成员函数及其作用已经在上述程序注释。我们可以发现,其中大部分内容包括了array<T,N>中的成员函数,且作用相似,如 begin() 指向首元素,end() 指向尾元素后面的一个位置。

注意事项

  • vector容器包括了成员函数 swap() 之外,还有一个 std::swap(x,y) 非成员函数,但注意两者必须是存储相同类型的元素。
  • vector容器的 swap() 成员函数交换了两个容器内的数据,也改变了其 size 大小。
  • vector容器可以初始化为空的容器,因为其长度可变,但是在初始化空的vector容器时,不能使用迭代器,因为对于空的 vector 容器来说,其 begin() 和 end() 都指向的是同一个位置。此时如果想初始化,可以通过调用push_back() 或 resize() 函数来初始化。
#include<iostream>
#include<vector>
using namespace std;
int main(){
    vector<int> val;

    for(auto iter = val.begin(); iter != val.end(); iter++)
    {//没有输出
        *iter = 1;
        cout<<*iter<<" ";
    }
    cout<<"**************"<<endl;
    val.resize(10);//改变vector容器大小
    for(auto iter = val.begin(); iter != val.end(); iter++)
    {
        *iter = 1;
        cout<<*iter<<" ";
    }
    getchar();
    return 0;
}

输出:

**************
1 1 1 1 1 1 1 1 1 1
  • 如果想增加容器的容量,还可以使用成员函数 reserve() 达成目的,但是申请了更多内存的同时,容器中元素的存放地址会发生改变(可以说是找了一块儿新的内存存储区来存储)
#include<iostream>
#include<vector>
using namespace std;
int main(){
    vector<int> val{1,2,4,5};
    cout<<"old address : "<<val.data()<<endl;
    val.reserve(10);
    cout<<"new address : "<<val.data()<<endl;
    for (auto i = val.begin(); i != val.end(); i++)
    {
        cout<<*i<<" ";
    }
    cout<<endl;
    cout<<"the val's size is : "<<val.size()<<endl;

    vector<int> temp{1,2,3,4};
    temp.resize(10);
    for (auto iter = temp.begin(); iter != temp.end(); iter++)
    {
        cout<<*iter<<" ";
    }
    cout<<endl;
    cout<<"the temp's size is : "<<temp.size()<<endl;
    getchar();
    return 0;
}

输出:

old address : 0xef4320
new address : 0xef4360
1 2 4 5
the val's size is : 4
1 2 3 4 0 0 0 0 0 0
the temp's size is : 10

可见调用 reserve() 后改变了地址,并且遍历后只显示了4个元素,这是因为 reserve() 开辟出来的空间并不代表就都是有效空间,只有 size() 的大小才是有效空间。

注意:如果你调用 reserve(n) ,其中 n 小于原本的容量,则这个函数什么作用都没有。

具体的 reserve() 和 resize() 之间的区别可以看看这几篇文章

http://c.biancheng.net/view/6770.html

插入操作 insert() 和 emplace() 详解

insert() 函数的功能是在 vector 容器的指定位置插入一个或多个元素。

具体用法 (4中插入方法) 如下:

#include<iostream>
#include<vector>

using namespace std;

int main()
{
    vector<int> vec{1,2,3,4,5,6};
    vector<int>::iterator iter;
    vec.insert(vec.begin()+2,10);//在第begin()+2 (3)个位置前插入int型元素 10
    for (auto&& val : vec)
    {
        cout<<val<<" ";
    }
    cout<<endl;
    vec.insert(vec.end()-1,3,9);//在最后一个元素之前插入 3 个int型元素 9
    for (auto&& val : vec)
    {
        cout<<val<<" ";
    }
    cout<<endl;
    vec.insert(vec.begin()+3,{10,9,8,7});//在第4个元素之前插入列表{10,9,8,7}
    for (auto&& val : vec)
    {
        cout<<val<<" ";
    }
    cout<<endl;   
    vector<int> add{9,9,6};
    vec.insert(vec.end(),add.begin(),add.end());//在最后插入整个vector容器add
    for (auto&& val : vec)
    {
        cout<<val<<" ";
    }
    cout<<endl;
    getchar();
    return 0;
}

输出:

1 2 10 3 4 5 6
1 2 10 3 4 5 9 9 9 6
1 2 10 10 9 8 7 3 4 5 9 9 9 6
1 2 10 10 9 8 7 3 4 5 9 9 9 6 9 9 6

emplace() 函数也是在指定位置前插入元素,不过每次只能插入一个元素,而不是多个。

当然其也比 insert() 函数效率高一些。

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> v{1,2,3};
    v.emplace(v.begin(),0);
    for(auto && val : v)
    {
        cout<<val<<" ";
    }
    cout<<endl;
    getchar();
    return 0;
}

输出:

0 1 2 3
删除操作pop_back()、erase()、remove()和clear() 详解

还是先上代码看看:

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

int main()
{
    vector<int> v{1,9,9,9,0,6,0,2};
    cout<<"test pop_back()"<<endl;
    cout<<"size is : "<<v.size()<<endl;
    cout<<"capacity is : "<<v.capacity()<<endl;
    cout<<"pop last one : "<<v.back()<<endl;
    v.pop_back();
    cout<<"size is : "<<v.size()<<endl;
    cout<<"capacity is : "<<v.capacity()<<endl<<endl;
    //此时v{1,9,9,9,0,6,0}
    cout<<"test erase()"<<endl;
    auto iter = v.erase(v.begin()+2);//删除指定位置元素,返回一个指向删除元素所在位置下一个位置的迭代器。
    for(auto i = iter; i != v.end(); i++ )//从迭代器后开始遍历
    {
        cout<<*i<<" ";
    }
    cout<<endl;
    cout<<"size is : "<<v.size()<<endl;
    cout<<"capacity is : "<<v.capacity()<<endl<<endl;
    //此时v{1,9,9,0,6,0}  
    cout<<"test another erase()"<<endl;
    iter = v.erase(v.begin(),v.begin()+3);//删除[first,last)区域的元素,并返回指向此区域之后一个位置的迭代器
    for(auto i = iter; i != v.end(); i++ )
    {
        cout<<*i<<" ";
    }
    cout<<endl;
    cout<<"size is : "<<v.size()<<endl;
    cout<<"capacity is : "<<v.capacity()<<endl<<endl;
    //此时v{0,6,0}    
    cout<<"test remove()"<<endl;
    iter = remove(v.begin(),v.end(),0);//删除指定区域内元素为 0 的所有元素
    for(auto i = v.begin();i != iter;i++)
    {
        cout<<*i<<" ";
    }
    cout<<endl;
    for(auto i = v.begin(); i != v.end() ; i++)
    {
        cout<<*i<<" ";
    }
    cout<<endl;
    cout<<"size is : "<<v.size()<<endl;
    cout<<"capacity is : "<<v.capacity()<<endl<<endl;
    //此时v{6,6,0}
    cout<<"test clear()"<<endl;
    v.clear();//删除容器中所有的元素
    cout<<endl;
    cout<<"size is : "<<v.size()<<endl;
    cout<<"capacity is : "<<v.capacity()<<endl<<endl;

    getchar();
    return 0;
}

输出:

test pop_back()
size is : 8
capacity is : 8
pop last one : 2
size is : 7
capacity is : 8

test erase()
9 0 6 0
size is : 6
capacity is : 8

test another erase()
0 6 0
size is : 3
capacity is : 8

test remove()
6
6 6 0
size is : 3
capacity is : 8

test clear()

size is : 0
capacity is : 8

pop_back(),函数用法很简单,即删除 vector 容器中最后一个元素,该容器的大小(size)会减 1,但容量不会改变。

erase(pos),删除 vector 容器中 pos 迭代器指定位置处的元素,并返回指向被删除元素下一个位置元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会发生改变。

erase(pos1,pos2),删除 vector 容器中 [pos1,pos2) 的元素,并返回指向被删除区域下一个位置元素的迭代器。该容器的大小(size)会减 pos2-pos1,但容量(capacity)不会发生改变。

remove(),删除容器中所有和指定元素值相等的元素,并返回指向最后一个元素下一个位置的迭代器。值得一提的是,调用该函数不会改变容器的大小和容量。

  • 注意:我们看输出可以发现通过remove() 删除元素后,大小没变,且对容器进行遍历后输出为 6 6 0 ,这是为什么呢?这是因为remove() 的实现原理是,在遍历容器中的元素时,一旦遇到目标元素,就做上标记,然后继续遍历,直到找到一个非目标元素,即用此元素将最先做标记的位置覆盖掉(即用 第二个6 覆盖了最初的 0,但原来的 6 没有背覆盖,最后一个 0因为后面没有元素了也不会背覆盖),同时将此非目标元素所在的位置也做上标记,等待找到新的非目标元素将其覆盖。

clear(),删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会改变 vector 的大小(变为 0),但不是改变其容量。