C++学习篇(7)-vector

 

更多精彩请关注微信公众号“爱折腾的码农”,如果大家感兴趣的,可以多多分享关注微信公众号,二维码见下图。
在这里插入图片描述

 

主要内容

​    本篇内容主要介绍STL六大组件之一的序列式容器(vector),容器其实就是各种数据结构;另外,迭代器部分的内容可以看看《STL源码剖析》,它的的主要作用是作为容器和算法之间的胶合剂,单独的算法和容器是没有意义的,需要用合适的方法将两者结合起来,因此这部分内容主要结合容器实现原理来讲。如果对文章内容感兴趣,欢迎大家多多关注公众号"爱折腾的码农"。原文链接:https://mp.weixin.qq.com/s/6SL6t158lPxSowp4Jl9BVA

迭代器

    定义:提供一种方法,保证在不暴露容器的内部实现细节的情况下能够依序访问容器中的各个元素。

容器

    定义:各种数据结构,其实就是用来存放数据的,例如:vector、list、deque、map、unordered_map,容器分为两类:序列式容器和关联式容器,从底层实现上来说容器是一种类模板。

 

序列式容器

    概念:其实就是类似于一维数组的概念,以线性排列来存储指定类型的数据,但是存储的数据并不一定是有序的(有序是指从大到小或从小到大)。

vector

   可变大小数组。支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢。

序列式容器(顺序容器)
vector可变大小数组。支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢。

deque

双端队列。支持快速随机访问。在头尾位置插入或删除速度很快
list双向链表。只支持双向顺序访问。在list中任何位置进行插入或删除操作速度都很快
forward_list单向链表。只支持单向顺序访问。在链表任何位置进行插入或删除操作速度都很快
array固定大小数组。支持快速随机访问,不能添加或删除元素
string与vector相似的容器,但专门用于保存字符。随机访问快。在尾部插入或删除速度快

vector

        其实C++语言本身提供了一个存储数组的序列式容器array,但是它是静态空间,一旦设置好大小就不能改变,因此STL设计了一款可以动态改变内存大小的序列式容器vector(其实底层还是基于数组实现的)。

       动态分配内存实现原理:分配内存好内存后,如果发现现有内存不够存放元素,则需扩充内存,主要就是另外分配一块新的内存空间,然后将旧地址元素复制到新的地址,最后将原来的空间释放。

 

vector的迭代器

 

vector数据结构

vector的数据结构非常简单:线性连续空间。它用两个迭代器start和finish分别指向配置的连续空间中目前已使用的范围,并且用end_of_storage指向整块连续空间的尾端。

 

 

 为什么多申请内存留做备用空间

        为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求量更大一些,以备将来可能的扩充(其实这也是容量的概念),就是一旦容量已经满了,下次再有新增元素,整个vector就要实现扩容了。如果频繁的扩容就需要频繁的申请内存和释放内存,这样比较影响性能。

 

vector元素的基本函数实现(本部分只介绍了部分,具体请看《STL源码剖析》)

vector扩容原理

    注意:vector的扩容可分成2倍扩容和1.5倍扩容,其中1.5扩容的话原空间可能还会被使用,不会另外寻找新的内存,但是2倍扩容一定需要另外寻找新的内存空间。

 

vector使用方法

    接下来主要说一下vector在实际中的使用,其实完全没有必要死记硬背这些,多刷一些题就自然而然记住了。

1、初始化和拷贝

    //初始化

    vector<int> ivec1;    //默认初始化,初始状态为空
    vector<int> ivec2 = {1, 2, 3};    //列表初始化vector对象
    vector<int> ivec3(10, -1);    //创建指定元素的元素, 10个int类型的元素,每个都被初始化为-1
    vector<int> ivec4(10);  //值初始化,10个元素,每个元素初始化为0
    
    //拷贝
    vector<int> ivec5(ivec1);   //把ivec1的元素拷贝给ivec2
    vector<int> ivec6 = ivec1;  //把ivec1的元素拷贝给ivec6

2、其他操作

    vector<int> v{1, 2, 3, 4, 5, 6, 7};
    for(auto &i : v)    //对于v中的每个元素(注意:i是一个引用)
       i *= i;         //求元素值的平方


    for(auto i : v)     //对于v中的每个元素
       cout << i << " ";   //输出该元素

 

    //迭代器输出元素,其中it的定义类型应该是 vector<int>::iterator it = v.begin();
    for(auto it = v.begin(); it != v.end(); ++it)
       cout << *it << " ";
    cout << endl;

 

3、vector迭代器失效问题

    vector<int> v{1, 2, 3, 4, 5, 6, 7};
    for(auto it = v.begin(); it != v.end(); ++it){
      if(*it == 3)
           v.erase(it);
    }

    注意,当使用v.erase(it)语句执行后,it就变成了一个野指针,如果对一个野指针进行 it++操作就会出现错误,因此在删除元素时上述代码需要写成下面这样。

 

    vector<int> v{1, 2, 3, 4, 5, 6, 7};
    for(auto it = v.begin(); it != v.end(); ++it){
       if(*it == 3)
           it = v.erase(it);
    }

    这样就不会出错的原因是:erase会返回下一个元素的有效迭代器(vector的可以理解为指针)

 

 

resize()和reserve()的区别?

        resize(size_type n)用来强制将容器改为存放n个元素。如果n小于当前vector对象大小的话,容器尾部的元素会被销毁。如果n大于当前大小,则新默认构造的元素添加到容器尾端。如果n大于当前容量,则在添加元素之前会进行重新分配新的内存。

        reserve(size_type n)强制将vector对象的容量改为不小于n;如果n小于当前容器,vector忽略它。

 

 vector对象大小和容量区别?

        大小(size)是指元素的个数(即已存放到内存空间的元素个数),容量(capacity)指的是分配内存的大小(即使用空间配置器分配的内存空间)。

 

        最后预告一下接下来几篇文章会写序列式容器list、deque、list和vector的区别、关联式容器map、unordered_map等,如果对内容感兴趣的话,欢迎关注本公众号。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值