c++ primer读书笔记——顺序容器

容器简单介绍

顺序容器中,元素在顺序容器中的顺序与其加入容器时的位置相对应。
关联容器中,元素的位置由元素相关联的关键字值决定。
所有容器类都共享公共的接口,不同容器按不同方式对其进行扩展。公共接口使容器的学习更加容易。
每种容器提供了不同的性能和功能的权衡。
一个容器就是一些特定类型对象的集合。
标准库还提供了三种容器适配器,为容器操作定义了不同的接口,来与容器的类型适配。

9.1 顺序容器概述

所有顺序容器提供了顺序访问元素的能力。
顺序容器在两个方面有不同的性能折中:
①向容器添加或从容器中删除元素的代价
②非顺序访问容器中元素的代价

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

将元素保存在连续内存空间的顺序容器:string vector array
特点:支持随机访问,但在中间位置插入或删除元素的速度很慢
将元素保存在不连续的内存空间的顺序容器:list,forward_list
特点:在任何位置插入或删除元素操作很快,不支持随机访问,额外内存开销大
deque的特点:支持随机访问,在头尾插入和删除元素的速度很快
deque的实现原理:deque采用一块所谓的map(不是STL中的map容器)作为主控,map是一小块连续的内存空间,每一个元素都是一个指针,指向另一段(较大的)连续空间,称为缓冲区。
整体架构如图:
在这里插入图片描述
deque最大的任务是在这些分段的定量连续空间上,维护其整体连续的假象,并提供随机存取的接口,代价是复杂的迭代器架构。
deque的迭代器应该能够指出分段连续空间在哪里,其次他必须能够判断自己是否已经处于其所在缓冲区的边缘,如果是,一旦前进或后退就必须跳跃到下一个或者上一个缓冲区。为了能够正确跳跃,deque必须随时掌握map。所以迭代器需要定义四个指针:
cur ——当前元素的指针
first ——当前元素所在缓冲区的起始指针
last ——当前元素所在缓冲区的结束指针
node——map中指向所在缓冲区的指针

forward_list和array是新c++标准增加的类型。
对顺序容器来说,size是一个快速的常量时间的操作。
现代c++程序应该使用标准库容器,而不是更原始的数据结构。

确定使用哪种顺序容器
除非你有很好的理由选择其他容器,否则使用vector
如果你的程序空间的额外开销很重要,不要使用list或forward_list
如果要求随机访问元素,使用vector或deque
如果要求在容器中间插入或删除元素,使用list或forward_list
如果需要在头尾位置插入或删除元素,不在中间位置插入或删除元素,使用deque

9.2 容器库概览

容器类型上的操作形成了一种层次:
1 某些操作是所有容器类型都提供的
2 另外一些操作仅针对顺序容器、关联容器或无序容器
3 还有一些操作只适合一小部分容器

每个容器都定义在一个头文件中,头文件名与类型名相同。
容器均定义为模板类,需要额外提供元素类型信息。
顺序容器几乎可以保存任意类型的元素。
可以定义一个容器,其元素类型是另一个容器。

通用容器操作
1 类型别名
iterator & const_iterator 迭代器 & 常量迭代器(只读)
size_type 无符号整型,容器大小
difference_type 带符号整数类型,两个迭代器间的距离
value_type 元素类型
2 构造函数
C c; 默认构造函数,构造空容器
C c1(c2); 构造c2的拷贝c1
C c(b,e); 构造c,将迭代器b和e指定的范围内的元素拷贝到c
C c{a,b,c…}; 列表初始化c
3 赋值与swap
c1=c2; 将c1中的元素替换成c2中元素
c1={a,b,c…} 将c1中的元素替换成列表中的元素
a.swap(b) 交换a,b的元素
swap(a,b) 同上
4 大小
c.size() c中元素的数目
c.max_size() c可保存的最大元素数目
c.empty() 若c中存储了元素,返回false,否则返回true
5 添加/删除元素(不适用array)
c.insert(args)
c.emplace(init)
c.erase(args)
c.clear() 删除所有元素
6 关系运算符
“==”“!=” 所有容器都支持
<,<=,>,>= 关系运算符(无序关联容器不支持)
7 获取迭代器
c.begin() c.end() 返回指向c的首元素和尾元素之后位置的迭代器
c.cbegin() c.cend() 返回cosnt_iterator
8 反向容器的额外成员(不支持forward_list)
reverse_iterator 按逆序寻址元素的迭代器
const_reverse_iterator 不能修改元素的逆序迭代器
c.rbegin() c.rend() 返回指向c的尾元素和首元素之前位置的迭代器
c.crbegin() c.crend() 返回 const_reverse_iterator

9.2.1 迭代器

迭代器有公共的接口:如果一个迭代器提供某个操作,那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的。
迭代器范围
一个迭代器范围由一对迭代器表示,左闭右开,一对迭代器必须指向相同的容器。
end最靠前可以与begin指向相同的位置,end不在begin之前。(编译器不会强制这些要求,需要程序员自己确保)
使用左闭合范围蕴含的编程假定
使用左闭合范围是因为这种范围有三种方便的性质:
①如果begin和end相等,则范围为空
②如果begin和end不等, 则范围至少包含一个元素,且begin指向该范围第一个元素
③可以对begin递增若干次,使得begin==end
基于以上性质,可以用一个循环来处理一个元素范围,保证是安全的

9.2.2 容器类型成员

size_type,difference_type,iterator,const_iterator
反向迭代器与正向迭代器相比,各种操作的含义也都发生了颠倒
如果需要元素类型,可以使用容器的value_type
如果需要元素类型的一个引用,可以使用reference或const_reference

9.2.3 begin和end成员

begin()和end()最常见的用途是形成一个包含容器中所有元素的迭代器范围。
begin()和end()有多个版本:带r的版本返回反向迭代器;以c开头的版本返回const迭代器
当不需要写访问时,应使用cbegin或cend

9.2.4 容器定义和初始化

除了array之外,其他容器的默认构造函数都会创建一个指定类型的空容器,可以接受指定容器大小和元素初始值的参数。
在这里插入图片描述
将一个容器初始化为另一个容器的拷贝有两种方法:可以直接拷贝整个容器;或者拷贝由一个迭代器对指定的元素范围。
当将一个容器初始化为另一个容器的拷贝时,两个容器的容器类型和元素类型必须相同。

#include <string>
#include <list>
#include <vector>
#include <deque>
using namespace std;
list<string> authors ={
   "zhangsan","lisi","wanger"};
vector<const char*
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值