C++ 学习笔记(9)顺序容器、容器适配器

C++ 学习笔记(9)顺序容器

参考书籍:《C++ Primer 5th》
API:容器库


9.1 顺序容器概述

在这里插入图片描述

  • string 和 vector 元素保存在连续的内存空间中。所以用下标计算地址时非常快。
  • forward list 的设计目的是达到与手写单项列表数据结构相当的性能。

9.2 容器库概述

class A
{
public:
	string name;
	A(string str) { name = str; }
};

void main()
{
	vector<A> v1(2, A("abc"));	// 使用构造函数初始化所有元素。
}

在这里插入图片描述

9.2.1 迭代器

  • 迭代器范围(iterator range):由两个迭代器表示,指向同一容器元素或元素之后的位置(begin 和 end)。

9.2.3 begin 和 end 成员

vector<A> v1;

auto it1 = v1.begin();	// it1 是 vector<A>::iterator 类型
auto it2 = v1.cbegin();	// it2 是 vector<A>::const_iterator 类型

9.2.4 容器定义和初始化

在这里插入图片描述

  • 将容器创建为另一个容器的拷贝有两种方法:
    • 直接拷贝:要求容器类型相同,其元素类型也相同。
    • 由迭代器指定元素范围:不要求容器类型相同,元素类型也可以不同(但能要转换)。
list<string> str1 = { "abc","jjj","2333" };
vector<const char *> ccp = { "fuck","that","shit" };

// 直接拷贝
list<string> str2(str1);		// 正确,容器类型相同,元素类型相同。
vector<string> vec(str1);		// 错误,容器类型不同。
list<const char *> ccp2(ccp);	// 错误,元素类型不同。

// 迭代器拷贝
forward_list<string> words(ccp.begin(), ccp.end());		// 正确,容器类型可以不同,元素类型不同但可以转换。
  • array具有固定大小,初始化时需要同时类型和指定大小。
  • 内置数组无法进行拷贝或对象赋值,但是array可以。
int digs[3] = { 1,2,3 };
int cpy[3] = digs;					// 错误,内置数组不支持拷贝或赋值

array<int, 3> digits = {1,3,5};
array<int, 3> copy = digits;		// 正确,但要求类型要完全相同

9.2.5 赋值和swap

在这里插入图片描述

  • swap交换两个相同类型容器的内容。元素本身并没有交换,交换的是两个容器的内部数据结构(即不对元素拷贝、插入、删除)。这样指向内容迭代器、引用和指针都在swap操作后不会失效。
  • swap交换两个array会真正交换元素(迭代器、指针和引用指向的位置不变,但是内容变了,所以是错误的),交换的时间和array中元素数目成正比。

9.2.6 容器大小操作

  • forward_list 支持max_size 和 empty,但不支持size。

9.2.7 关系运算符

  • 类似string:
    • 两个容器元素对应相等时,容器相等。
    • 容器大小不同,但小的都对应相等时,数目少的大于数目多的。
    • 两个容器比较结果也取决于第一个不同的元素比较结果。

9.3 顺序容器操作

9.3.1 向顺序容器中添加元素

在这里插入图片描述

  • 对于vector和string,除了尾部,其他位置添加元素都需要移动元素。还可能引起整个对象存储空间重新分配。
  • 对于deque,除了首尾,都要移动元素。
  • insert返回的是指向新插入元素的迭代器。
  • 当用一个对象来初始化容器时,或将一个对象插入到容器(push或insert),实际上放入到容器中的对象值的拷贝,而非本身。
  • 使用emplace操作是构造而非拷贝。直接在容器中构造,不会产生临时对象。
class A
{
public:
	string name = "nothing";
	A() = default;
	A(string str) { name = str; }
};

void main()
{
	vector<A> vecA;
	vecA.emplace_back("shit");	// 在容器内部中直接构造元素,调用了A(string str)的构造函数。
	vecA.emplace_back();		// 添加了使用默认构造函数的对象。

	system("pause");
}

9.3.2 访问元素

在这里插入图片描述

  • front、back、下标、at:返回的都是引用。
vector<string> svec;
cout << svec[0];		// 运行错误。
cout << svec.at(0);		// 抛出out_of_range异常。

9.3.3 删除元素

在这里插入图片描述

  • erase删除元素后,返回指向删除元素后位置的迭代器。

9.3.4 特殊的forward_list操作

在这里插入图片描述

  • 在删除一个元素时,会影响到前一个元素的信息(即指向下一个元素的地址)。要删除一个元素,就要在前一个元素调用erase_after。

9.3.5 改变容器大小

在这里插入图片描述

9.3.6 容器操作可能使迭代器失效

  • 容器添加元素:
    • vector 或 string:
      • 重新分配空间时:迭代器、指针引用都失效。
      • 没有重新分配空间:插入之前都有效,之后的都失效。
    • deque:
      • 插入首尾之外:都会失效。
      • 插入首位置:迭代器失效,指针引用仍有效。
    • list 或 forward_list:
      • 一直有效。
  • 容器删除元素(所有被删除的元素的迭代器、指针、引用都会失效):
    • vector 或 string:
      • 之前的都有效,之后的都失效。
    • deque:
      • 删除首尾之外:都失效。
      • 删除尾元素:迭代器失效,指针引用有效。
      • 删除首元素:都有效。
    • list 或 forward_list:
      • 一直有效。

9.4 vector 对象是如何增长的

在这里插入图片描述

  • 每次需要分配新内存空间时,将当前容量翻倍。
  • 如果需求小于等于当前容量,reserve什么都不做。
  • 调用shrink_to_fit只是一个请求,标准库并不保证退还内存。
  • 仅在插入或调用resize 或 reserve 时,才有可能重新分配空间。即删除(或全部清除)时,不会改变容量大小。

9.5 额外的string 操作

9.5.1 构造string的其他方法

原来介绍的string:C++ 学习笔记(3)命名空间using、字符串、string、vector、迭代器、数组

在这里插入图片描述

  • 用const char*构造创建string时,字符串必须以空字符作为结尾,因为拷贝操作在遇到空字符时才会停止。

在这里插入图片描述

9.5.2 改变string的其他方法

  • replace是调用erase和insert的一种简写。

在这里插入图片描述
在这里插入图片描述

9.5.3 string 搜索操作

  • npos:const_string::size_type类型,初始值-1(无符号型,即最大值)。

在这里插入图片描述

9.5.5 数值转换

// 找到字符串第一个数值,获取其数字字符串,转换成浮点数。
string s = "pi = 3.14";
float d = stod(s.substr(s.find_first_of("+-.0123456789")));

在这里插入图片描述


9.6 容器适配器

  • 适配器(adaptor):标准库的一个通用概念。容器、迭代器和函数都适用。本质上是一种机制,能使某种事物的行为看起来像另外一种事物一样。(就像任天堂给switch加个几块纸板一样。)

在这里插入图片描述

  • 默认情况下,stack和queue都是基于deque实现的,priority_queue是在vector。
  • 适配器需要有添加和删除能力(要求是顺序容器)。
    • stack要求拥有back、push_back、pop_back:
      • vector 、deque 、list。
    • queue要求拥有back、push_back、front、pop_front:
      • deque、list。
    • priority_queue要求拥有front、push_back、pop_back,同时要有随机访问的能力:
      • vector 、deque。

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值