【C++】-- STL之vector详解

目录

一、vector类

二、vector类成员 

 1.vector类对象构造

 2.vector元素访问符

 3.vector迭代器

 4.vector模板

 5.vector拷贝构造

 6.vector容量

(1)vector增容机制 

(2)reserve()和resize()

(3)size()

(4)empty()

 7.vetor尾插和尾删

 8.vector在任意位置插入和删除

(1)插入 

(2)删除 

9.find()

10.swap() 

 三、迭代器失效

1.迭代器失效的情况

2.如何解决迭代器失效


【C++】-- STL之vector详解_第1张图片

一、vector类

vecotr是可以改变大小的数组的序列容器,其特点有:

(1)vector采用连续空间来存储元素,可以使用下标访问vector元素,访问元素和数组一样方便。vector大小可以动态改变,而且会被容器自动处理,这一点数组无法做到。

(2)vector使用动态分配分配数组来存储元素,插入新元素时,vector数组为了增加存储空间,会分配一个新数组,再把所有元素全部移动到这个数组里,代价相对高一些。

(3)vector会分配额外的空间来满足可能的增长,因为分配的存储空间比实际需要的的存储空间更大。vector以动态增长的方式管理存储空间。

(4)vector在访问元素、末尾添加删除元素时很高效,在其他位置插入删除需要挪动元素,效率低。

二、vector类成员 

 1.vector类对象构造

//构造空的vector
explicit vector (const allocator_type& alloc = allocator_type());
	
//构造一个vector,有n个元素,每个元素值为val
explicit vector (size_type n, const value_type& val = value_type(),
                 const allocator_type& alloc = allocator_type());	

//构造一个vector,值为InputIterator的first到last之间的元素
template 
         vector (InputIterator first, InputIterator last,
                 const allocator_type& alloc = allocator_type());	

//使用x拷贝构造一个vector
vector (const vector& x);
#include
#include

using namespace std;
int main()
{   
    vector v;//构造一个没有元素的空容器
    vector v1(3, 5);//构造一个有3个元素的容器,每个元素的值都为5
    vector v2(v1.begin(),v1.end());//构造一个从v1.begin()到v1.end()顺序及相同值的容器
    vector v3(v2);//以与v2相同的顺序及值拷贝构造一个容器

    //插入4个元素
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

    return 0;
}

 2.vector元素访问符

      reference operator[] (size_type n);      //可读可写
const_reference operator[] (size_type n) const;//只读

vector使用operator[ ]遍历元素,像数组一样:

	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

【C++】-- STL之vector详解_第2张图片

 3.vector迭代器

迭代器是一种容器可以统一使用的遍历方式,因此vector也支持使用迭代器遍历 

      iterator begin();      //可读可写
const_iterator begin() const;//只读

      iterator end();        //可读可写
const_iterator end() const;  //只读

      reverse_iterator rbegin();       //反向迭代器 可读可写
const_reverse_iterator rbegin() const; //反向迭代器 只读

      reverse_iterator rbegin();       //反向迭代器 可读可写
const_reverse_iterator rbegin() const; //反向迭代器 只读

 (1)迭代器

①可读可写

    vector::iterator it = v.begin();//可读可写
	while (it != v.end())
	{
        *it += 2;
        cout << *it << " ";
        it++;
	}
	cout << endl;

 【C++】-- STL之vector详解_第3张图片

②只读

    vector::const_iterator it = v.begin();//只读
	while (it != v.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

【C++】-- STL之vector详解_第4张图片

(2)反向迭代器 (这段代码屏蔽了(1)的迭代器)

①可读可写 

    vector::reverse_iterator rit = v.rbegin();//可读可写
    while (rit != v.rend())
    {
        *rit += 2;
        cout << *rit << " ";
        rit++;
    }
    cout << endl;

【C++】-- STL之vector详解_第5张图片

②只读 

    vector::const_reverse_iterator rit = v.rbegin();//只读
    while (rit != v.rend())
    {
        cout << *rit << " ";
        rit++;
    }
    cout << endl;

【C++】-- STL之vector详解_第6张图片

 4.vector模板

前面的PrintVector( )只能打印元素为int的vector,如果vector元素类型不是int,而是char或float类型,该如何打印呢?使用模板可以实现,有关模板的详细说明请阅读文章【C++】-- 模板详解

//打印
template//类模板定义
void PrintVector(const vector& v)
{
    //指定参数类型
    vector::const_iterator it = v.begin();//只读
    while (it != v.end())
    {
        cout << *it << " ";
        it++;
    }
    cout << endl;
}
int main()
{
    vector v;//定义一个vector,该vector里面的元素都是int型的
    //插入4个int元素
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    PrintVector(v);

    string s1 = "Hello world";
    vector v4(s1.begin(), s1.end());
    PrintVector(v4);
    
    vector v5;
    插入4个float元素
    v5.push_back(1.1);
    v5.push_back(2.2);
    v5.push_back(3.3);
    v5.push_back(4.4);
    PrintVector(v5);
    
    return 0;
}

【C++】-- STL之vector详解_第7张图片

注:如果编译报vector::const_iterator it = v.begin();代码有如下错误:

调试-解决方案调试属性-语言-符合模式-否就可以编译通过了【C++】-- STL之vector详解_第8张图片

 5.vector拷贝构造

    vector v6;
    v6.push_back(string("delia"));

    vector v7(v6);//用v6拷贝构造v7
    PrintVector(v7);

    vector v8(v5);//用v5拷贝构造v8
    PrintVector(v8);

 【C++】-- STL之vector详解_第9张图片

 6.vector容量

(1)vector增容机制 

在VS下执行这段代码: 

void test_vector3()
{
    size_t sz;
    std::vector foo;
    sz = foo.capacity();
  
    std::cout << "making foo grow:\n";

    for (int i = 0; i < 100; i++)
    {
        foo.push_back(i);
        if (sz != foo.capacity())
        {
            sz = foo.capacity();
            std::cout << "capacity changed:" << sz << endl;
        }
    }
}

 发现增容的过程是大概按照1.5倍增容的【C++】-- STL之vector详解_第10张图片

 同样的代码在linux下运行,发现是2倍增容的

【C++】-- STL之vector详解_第11张图片

因此 ,在不同的编译器下增容机制不同。

(2)reserve()和resize()

void reserve (size_type n);//开辟n个元素空间
void resize (size_type n, value_type val = value_type());//开辟n个元素空间,并将每个元素默认初始化为val

 如果加上reserve(),那么会提前知道要开多少空间,就提前开好了,避免后面再开空间 

void test_vector3()
{
    size_t sz;
    std::vector foo;
    sz = foo.capacity();
    foo.reserve(100);
  
    std::cout << "making foo grow:\n";

    for (int i = 0; i < 100; i++)
    {
        foo.push_back(i);
        if (sz != foo.capacity())
        {
            sz = foo.capacity();
            std::cout << "capacity changed:" << sz << endl;
        }
    }
}

【C++】-- STL之vector详解_第12张图片

linux下运行也是同样结果 ,也是提前知道要开100个字节的空间,就提前开好了

 监视如下代码发现,reserve()之后,capacity变了,但是size没变;resize()之后,capacity变了,size也变了,且每个元素都被默认赋值为0

    vector v1;
    v1.reserve(10);

    vector v2;
    v2.resize(10);

 【C++】-- STL之vector详解_第13张图片

(3)size()

 返回vector元素个数

size_type size() const;

求v5的size() 

    vector v5;
    //插入4个元素
    v5.push_back(1.1);
    v5.push_back(2.2);
    v5.push_back(3.3);
    v5.push_back(4.4);
    cout << v5.size() << endl;

【C++】-- STL之vector详解_第14张图片

(4)empty()

判断vector是否为空,为空返回1,不为空返回0

bool empty() const;

判断v5是否为空 

cout << v5.empty() << endl;

 【C++】-- STL之vector详解_第15张图片

 7.vetor尾插和尾删

void push_back (const value_type& val);//尾插元素
void pop_back();//尾删元素

 向v5尾插元素和尾删元素

    v5.push_back(5.5);
    PrintVector(v5);
   
    v5.pop_back();
    PrintVector(v5);

【C++】-- STL之vector详解_第16张图片

 8.vector在任意位置插入和删除

(1)插入 

iterator insert (iterator position, const value_type& val);//插入val到position位置
void insert (iterator position, size_type n, const value_type& val);//将n个val插入到position位置
template 
    void insert (iterator position, InputIterator first, InputIterator last);//将值为InputIterator的first到last之间的元素插入到position位置
    vector v5;
    //插入4个float元素
    v5.push_back(1.1);
    v5.push_back(2.2);
    v5.push_back(3.3);
    v5.push_back(4.4);
    v5.push_back(5.5);
    
    v5.insert(v5.end(), 6.6);//在v5末尾插入6.6
    PrintVector(v5);
    
    v5.insert(v5.begin(), 2,0);//在v5开头插入2个0
    PrintVector(v5);

    vector v6;
    v6.push_back(7.7);
    v6.push_back(8.8);

    v5.insert(v5.begin(), v6.begin(),v6.end());//在v5开头插入v6
    PrintVector(v5);

【C++】-- STL之vector详解_第17张图片

(2)删除 

iterator erase (iterator position);//删除某一位置元素
iterator erase (iterator first, iterator last);//删除迭代器first和last之间的元素
    v5.erase(v5.begin());//删除v5开头元素
    PrintVector(v5);

    v5.erase(v5.begin(), v5.begin()+2);//从v5开头删除2个元素
    PrintVector(v5);

【C++】-- STL之vector详解_第18张图片

 insert()和erase()之后需要挪动元素,时间复杂度为O(N),效率较低,不推荐用insert()和erase()插入删除元素

9.find()

在迭代器区间内查找元素,find函数实现在algorithm中,可以给所有容器使用,因此要使用find函数,就要include

template 
   InputIterator find (InputIterator first, InputIterator last, const T& val);//在InputIterator迭代器first和last区间内查找val元素的位置

注意:迭代器区间是左闭右开,因此能取到第一个位置,但取不到最后一个位置 

    vector::iterator pos = find(v5.begin(), v5.begin() + 3, 1.1);//在第一个元素和第四个元素(左闭右开,不包含第四个元素)之间查找值为1.1的元素位置
    v5.erase(pos);//删除1.1位置的元素,即删除1.1

     PrintVector(v5);

【C++】-- STL之vector详解_第19张图片

10.swap() 

将this指针指向的对象的内容和x进行交换 

void swap (vector& x);

如:

    vector v1;
    v1.push_back(20);

    v.swap(v1);//交换v和v1的元素

    PrintVector(v);
    PrintVector(v1);

【C++】-- STL之vector详解_第20张图片

vector自己实现了swap(),相比较,库里的swap需要3次深拷贝,代价比较高:

template  void swap (T& a, T& b);
{
    T c(a); a=b; b=c;
}

 三、迭代器失效

1.迭代器失效的情况

 (1)在v中插入元素1,2,3,4,5后,在3前面插入30

    vector v;

    //插入6个int元素
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    //在3的前面插入30
    vector::iterator pos = find(v.begin(), v.end(), 3);//查找3的位置
    if (pos != v.end())
    {
        v.insert(pos, 30);
    }
    PrintVector(v);

【C++】-- STL之vector详解_第21张图片

但是当删除30时,执行如下代码,程序崩了

    v.erase(pos);
    PrintVector(v);

【C++】-- STL之vector详解_第22张图片

 这是因为先查找3,找到后挪动3的位置及之后的数据,插入30,3已经挪走了,但pos还指向原来的位置,也就是现在30的位置。再erase的时候,pos失效了,因为pos的意义变了,不再指向3了,所以程序崩溃。

(2)如下代码当删除所有偶数时,程序会崩

    vector v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    v.push_back(6);

    //删除v中所有的偶数
    vector::iterator it = v.begin();
    while (it != v.end())
    {
        if (*it % 2 == 0)
        {
            v.erase(it);
        }
        it++;
    }

    PrintVector(v);

执行过程:end不固定,删除数据后,每次都会去重新拿取,end是最后一个数的下一个位置

 【C++】-- STL之vector详解_第23张图片

 而且执行过程中,由于删除数据后,it++了,迭代器的意义变了,所以结果一定不正确。

迭代器失效有两种情况:

(1)pos意义变了,插入数据以后,pos不再指向3,而是指向30,导致erase(pos)没有达到删除3的目的,反而删除的是30

(2)程序可能崩溃,pos变成了野指针

2.如何解决迭代器失效

在使用迭代器之前,对迭代器重新赋值

对于(1)使用迭代器之前,对迭代器重新赋值

    vector v;

    //插入6个int元素
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    //在3的前面插入30
    vector::iterator pos = find(v.begin(), v.end(), 3);
    if (pos != v.end())
    {
        v.insert(pos, 30);
    }

    PrintVector(v);

    //使用迭代器之前,对迭代器重新赋值
    pos = find(v.begin(), v.end(), 3);
    //然后再使用迭代器
    if (pos != v.end())
    {
        v.erase(pos);
    }
    PrintVector(v);

【C++】-- STL之vector详解_第24张图片

对于(2)每次使用迭代器之前,对迭代器重新赋值,当it为偶数的位置时,删除偶数后,it不用++

    vector v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    v.push_back(6);

    //删除v中所有的偶数
    vector::iterator it = v.begin();
    while (it != v.end())
    {
        if (*it % 2 == 0)
        {
            //每次使用迭代器之前,对迭代器重新赋值
            it = v.erase(it);//删除偶数后,it不用++
        }
        else 
        {
            it++;//奇数,it++
        }
        
    }

    PrintVector(v);

【C++】-- STL之vector详解_第25张图片

你可能感兴趣的:(C++,c++,开发语言)