C++基础语法:STL之容器(2)--序列容器中的vector

前言

       "打牢基础,万事不愁" .C++的基础语法的学习

引入

        序列容器的学习.以<C++ Prime Plus> 6th Edition(以下称"本书")内容理解

        本书中容器内容不多只有几页.最好是有数据结构方面的知识积累,如果没有在学的同时补上.

序列容器回顾

        C++基础语法:STL之容器(1)--容器概述和序列概述-CSDN博客 

        序列容器内元素按严格线性顺序排列,至少是正向迭代器(含以上).序列容器包括deque(双端队列),forward_list(单链表),list(双向链表),queue(队列),priority_queue(优先队列),stack(栈),vector(动态数组),array(替代数组的容器)

        容器的内容非常重要,但不在api如何调用,而在于对数据结构的认识.程序本质上就做了两件事,处理数据和数据交互(CPU和内存,内存和硬件之间).数据结构除了表示某个类型的数据集合,也是在计算机中的存储方式.对软件性能有较大的影响.不过也不用担心,STL容器提供了方便的使用,即使理解不那么深,也一样可以写程序

数据结构概览 

        数据结构加上算法等于数据集合.算法操作包括基本的增加集合元素,删除集合元素,查找集合元素(可选),加上其他想实现的算法. 

        学习数据结构,最好在脑子里形成一个画面,关于数据添加,数据删除,和查询,从图中反映出来

分析容器时,如果没有源码做参照,理解起来很吃力.但又没有现成代码,所以下列代码完全是揣测.

注意:下列代码为了练手,试图重现逻辑,不保证准确

vector容器 

        特点:物理容器是数组,逻辑上是动态变化的数组

        本书中vector描述

        第1部分:前面介绍了多个使用vector模板的例子,该模板是在vector头文件中声明的。简单地说,vector是数组的一种类表示,它提供了自动内存管理功能,可以动态地改变vector对象的长度,并随着元素的添加和删除而增大和缩小。它提供了对元素的随机访问。在尾部添加和删除元素的时间是固定的,但在头部或中间插入和删除元素的复杂度为线性时间.(本段黑体字是本书原话)

         部分解读和代码:

         ----在vector头文件中声明,自动内存管理

        1.建立vector容器,假设数据类型为T


template<class T>             //声明容器类
class vector{
    int n;                    //n表示vector内元素数目
    T* head;                  //指针指向动态数组
public:
    vector();                 //构造函数
    void push_back(T val);    //尾部添加元素  
}

template<class T>
vector::vector(){
    n=1;                      //初始化时内含1个元素
    /*这里是硬编码,编程要尽力避免这种情况*/
    head=new T[1];            //申请1个元素的内存空间,n=0也不会报错
}

        初始个数为1,但里面不放数据,和链表里的"头结点"类似 

        2.尾部添加元素

void push_back(T val){
    n++;                           //索引先加1; 
    T *newVector=new T[n];         //再次申请一段内存空间   
    /*数组首个元素始终被空置*/
    while(n>2){                    //除了插入第一个元素外的其他情况
        for(int i=1;i<n-1;i++){
            newVector[i]=head[i];  //复制旧数组head到新数组newVector当中  
        }
        break;                     //for循环完毕后跳出while                        
    }
    newVector[n-1]=val;            //新元素插入到数组末尾,插入第一个元素时,n=2
    T* tmp=head;                   //标识原来的数组
    head=newVector;                //把添加完数据的数组作为新的vector容器    
    delete[] tmp;                  //删除原来数组head
}

        代码思路:

        1>插入元素:

        申请一块内存空间,把索引值加1.新数组末尾的索引值是n-1;其他数据(索引从1到<n-1)的部分对原数组数据进行复制. 当第一次插入的时候发现for循环不符,单独用while写一段.数组首个元素--索引为0的那个始终空置,没有初始化,也从不访问.

        2>删除原来的物理容器:

        和链表一样,先用tmp做标识,指向他所在的数据块,然后将新的容器建立,最后删除tmp.

        3.删除元素(单个)

        序列提供的api中有个erase(p)的算法,以传入迭代器为参数

        思路:生成一个新容器,删掉迭代器指向的数据,并返回新数组.

        如果以索引为参数容易写.可以参照C语言的"动态数组",以迭代器为参数也差不多,因为没有迭代器转化索引的api,就不展开了.

        4.随机访问

        运算符重载operator[](int order){}; 这个比较基础.本书P380第11章"使用类"

        5.在尾部添加和删除元素的时间是固定的,但在头部或中间插入和删除元素的复杂度为线性时间

        表16.7序列的要求里有insert函数和erase函数,也是以迭代器为参数的,在头部或中间插入和删除,要访问vector容器中所有元素,所以复杂度为线性时间.

         第2部分:除序列外,vector还是可反转容器(reversible container)概念的模型。这增加了两个类方法:rbegin( )和rend( ),前者返回一个指向反转序列的第一个元素的迭代器,后者返回反转序列的超尾迭代器

        部分解读和代码: 

         这里又有个可反转容器的概念,他和迭代器一样属于概念上的设计.

        回顾迭代器,有了迭代器的概念后,设计接口api

/*伪代码,object是容器类对象,it为迭代器iterator对象*/
/*用途:遍历容器对象的数据*/
for(it=object.begin();it!=object.end();it++){
    cout<<*it<<endl;
}

        以此为依据,设计迭代器类和迭代器对象函数it++,*it,及容器类函数begin()和end()

        迭代器的设计流程:概念→接口设计→内容设计.

        可反转容器的接口在本书P698页

         可反转容器的目的是反向遍历容器对象,可以在迭代器类的基础上做.例如:rbegin()函数返回超尾迭代器-1;rend()函数返回begin()迭代器.运算符重载operator--(),修改迭代器属性(指向容器类对象的指针).

        注意:可反转容器需要--的操作,查表本书P690表16.4"迭代器的性能",推导出只有实现双向迭代器以上的容器,才能做可反转容器. 从这里理解在迭代器设计时,根据功能不同,划分迭代器的层次.

        第3部分:vector模板类是最简单的序列类型,除非其他类型的特殊优点能够更好地满足程序的要求,否则应默认使用这种类型

        关键词:非常好用的数据结构,默认使用类型,首选的数据结构类型.

小结

        STL容器本身不难使用,关键是在学习使用过程中,理解设计者的设计理念 

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jllws1

你的鼓励是我创作的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值