顺序容器(上)

来源:互联网 发布:免费的会计软件 编辑:程序博客网 时间:2024/06/05 22:32

容器:特定类型对象的集合(模板)
通用操作:CP295(表9.2)
顺序容器:顺序与元素加入容器的位置有关

//可变大小数组#include <vector>

不能在循环中向vector中添加对象

//与vector相似,专门用于保存字符#include <string>
//c++11 数组类型(固定大小)#include <array>          
//c++11 单向链表,,没有size操作#include <forward_list>   
//双向链表,#include <list>  
//双端队列#include <deque>          

容量类型

size_type 
  • 也可用于下标索引,因为编译器不会检查下标是否越界,所以该类型为unsigned可以确保下标不会小于0
  • 只能对已存在的下标运算符执行下标操作

访问:

  • 支持快速随机访问:

    • vector(保存在连续空间)
    • string(保存在连续空间)
    • array
    • deque
  • 支持单向顺序访问:

    • forward_list
  • 只支持双向顺序访问:

    • list

快速插入删除:

  • 任何位置:
    • forward_list
    • list
  • 头尾:
    • deque
  • 尾部:

    • string
    • vector
      (在尾部之外需要移动后面的元素,可能需要额外分配空间)
  • 禁止:

    • array

选用原则:

  1. 相比内置数据结构推荐使用容器
  2. 通常首选vector
  3. 按照程序对数据读写的需求:
    应用中占主导地位的操作决定容器的选择(即当访问和插入删除的要求无法兼容)
    注意当

    1. 只有在读取输入时需要在容器中间位置插入元素
    2. 需要随机访问

    此时

    1. 如果必须要在中间插入,可以先使用list,再将内容拷贝到vector
    2. 如果不是,可以在vector中插入后调用sort函数进行排序

4 无法确定时,选择使用迭代器访问vector和list

这里写代码片

独享操作:CP299(表9.3)
初始化

  • 默认初始化为空容器(除array皆可用)
vector<int> vec;//当元素类型没有默认构造函数时需要传递初始化器vector<int> vec(init);     
  • 圆括号:构造(除array皆可用)
vector<int> vec(10);//10个元素vector<int> vec(10,1);//10个为1的元素vector<string> vec(10);//错误
  • 花括号:
    • 列表初始化
    • 除array皆可用
    • 只有在无法执行列表初始化的时候才会考虑其他的初始化方式
vector<int> vec{10};//一个为10的元素vector<int> vec{10,1};//一个为10和为1的元素 
vector<string> vec{ "hi" };//无法使用列表初始化,尝试使用默认值来初始化vector<string> vec{10};//10个元素 vector<string> vec{ 10,"hi" };//10个都是"hi"的元素//当元素类型没有默认构造函数时必须指定初始值

拷贝容器的一部分进行初始化

//通过指定范围初始化(除array皆可用)//类型必须可以相互转换vector<int> vec(ivec.begin(), ivec.end());

拷贝容器进行初始化

//ivec和vec的类型(元素和容器)相同vector<int> vec(ivec); vector<int> vec=ivec;//array的size必须相同 

列表初始化
当内置类型的初始值存在丢失信息的风险,(例如类型转换时丢失精度),编译器将报错。CP39

//对于array来说数量不够时会进行值初始化vector<int> vec{ 1,2,3,4,5 };vector<int> vec={ 1,2,3,4,5 };//多个初始值只能使用列表初始化
array<int,10> a;

赋值

  • 如果容器大小不同,赋值后为右边容器的大小
  • array的元素类型必须相同
  • 导致左边的迭代器,引用和指针失效
c1=c2;c={a,b,c};//除array皆可用assign CP302

swap

  • 类型必须相同
  • 速度更快(除array外只交换容器内部的数据结构,不交换元素)
  • 对于array会交换元素
  • 除array和string不会使迭代器,引用和指针失效(但指向的元素变换了所属的容器)
swap(c1,c2)//尽量使用非成员版c1.swap(c2)
vector<string> sv1(5);vector<string> sv2(10);auto iter=sv1.begin();/*交换后vec1有10个元素,vec2有5个元素    交换的是整个容器内容*/swap(sv1,sv2);//交换后iter指向sv2[0]

assign

  • 仅顺序容器使用
  • 类型相容即可
seq.assign(b,e)seq.assign(i1)seq.assign(n,t)

大小

c,size()c.max_size()//可保存的最大元素数目c.empty()

关系运算符:

  • 除无序关联容器皆可
  • 容器和元素类型必须相同
  • 进行元素的逐对比较
  • 元素的类型必须定义相应的比较运算符

    1. 容器的size和元素都相同才等于
    2. size不同时,size较小时容器的值都等于则小于
    3. 第1次出现相异字符的对比结果

添加

  1. array不可用
  2. 添加的是对象的拷贝,而不是对象本身
  3. 可能导致系统需要重新分配足够的内存并移动
    (对于vector和string的迭代器,指针和引用都会失效)
  4. emplace操作构造(并非拷贝)元素
  5. 对于提供参数必须保证定义了对应的构造函数
//vector和string不支持(需要移动所有元素)//在头部创建c.push_front(t);//先根据参数创建局部临时对象,再放入容器c.emplace_front(t);//在容器内部根据参数直接创建对象
//在尾部创建//forward_list不支持c.push_back(t);c.emplace_back(t);
c.insert(iter, p1);
  • 插入到迭代器之前的位置
  • 返回指向新添加的第1个元素的迭代器
list<string> lst;auto iter=lst.begin();while(cin>>word)     iter=lst.insert(iter,word);
  • 可以用其代替push_front,但是根据前面容器的性质可能会很耗时
  • 同时支持插入范围内元素
//指定数量的元素vec2.insert(iter2, n, t);//迭代器位置之前插入n个t元素                         
//迭代器范围ivec3.insert(iter3, ivec2.begin(), ivec2.end());//迭代器的范围不能是同一个容器 
//列表    ivec4.insert(ivec.begin(), {1,1,1});
  • forward_list有专有版本的insert_after和emplace_after

  • 副作用

    • vector和string:
      如果存储空间并未重新分配,只有插入位置之后的迭代器,指针和引用都会失效。
    • deque:
      插入到首尾位置之外会导致迭代器,指针和引用都会失效。
      在首位置添加只会导致迭代器失效。

访问:

  • 返回引用
  • 有时比begin()/end()更加方便
  • 禁止使用失效的迭代器,指针和引用(添加/删除的副作用)
  • 在循环中添加/删除会注意保持迭代器保持正确的更新
  • 由于尾后迭代器经常失效,必须重新调用end
auto begin=v.begin();while( begin != v.end() ){…}
  • 容器为空时函数未定义,使用前必须确保容器非空
c.front()  //返回首元素的引用

forward_list不支持

c.back()   //返回尾元素的引用
  • 只适用于支持随机访问的容器
    程序必须检查保证下标不会越界
c[n]  //n为无符号整数,超出size时函数未定义//建议使用c.at(n)  //n为无符号整数,超出size时抛出out_of_range异常

删除

  • 不适用于array
  • 必须保证被删除的元素是存在的,否则函数未定义
  • -禁止使用失效的迭代器,指针和引用
  • 如果需要则在pop之前保存被抛出的元素
    • 删除尾元素
c.pop_back();   //除forward_list外皆可

删除头元素

c.pop_front();  //除vector和string外皆可
  • forward_list有专有版本的erase_after
    返回被删除元素的下一个元素的迭代器
c.erase(iter)   //删除迭代器p指向的元素,

当e为尾后迭代器时,返回尾后迭代器

vec.erase(iter1,iter2)   //删除迭代器(b, e)范围内的元素
  • 删除所有元素
c.clear()
  • 副作用
    • 尾后迭代器总会失效
    • 指向被删除元素的迭代器,指针和引用都会失效。
    • vector和string:
      删除位置之后的迭代器,指针和引用都会失效。
    • deque:
      删除首尾位置之外的元素会导致迭代器,指针和引用都会失效。

改变容器大小

  • array除外
  • 当size大于n时,后面的元素被删除
c.resize(n)
  • 当size小于n时,将新元素添加到后面
c.resize(n)//新元素被默认初始化c.resize(n,t)//新元素都初始化为t

容器容量管理

  • 只适用于vector和string
    由于vector/string的元素都是连续存储,为了在添加操作时减少重新分配的次数,实现分配时会额外预留一些空间备用。
c.capacity()  //现分配的内存空间可以容纳的元素数量
  1. 当n>c.capacity()时,该函数才会改变容量(≧n);反之函数不做任何改变。
  2. 注意与resize的区别
  3. 尽量不要分配新的空间
c.reserve(n)   //通知容器需要容纳的最小元素数量
  • 只适用于deque、vector和string
    可以向系统请求退回多余的内存空间(不一定执行)
c.shrink_to_fit()  //将capacity()的数量减少为size()

forward_list
由于添加/删除单向链表的元素会改变序列的链接,为了维护,必须访问其前驱以便改变链接。

  • 返回指向首元素之前位置的迭代器(无法解引用)
    对forward_list需要2个迭代器
lst.before_begin()lst.before_cbegin()
  • 必须保证迭代器不为尾后迭代器
//将t插入到p的后面lst.insert_after(p,t)lst.insert_after(p,n,t)//范围不能在lst内,范围为空返回plst.insert_after(p,b,e)
lst.insert_after(p,{…})
//在指定位置后创建新元素,返回指向新元素的迭代器emplace_after(p,t)
  • 必须保证迭代器不为尾后/指向尾元素的迭代器
//删除p之后的元素lst.erase_after(p)//删除从b开始到(不包括)e的元素lst.erase_after(b,e)
原创粉丝点击