C++ Primer 第9章顺序容器

news2024/10/6 14:27:00

9.1 顺序容器概述

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

确定使用哪种顺序容器

通常使用vector是最好的选择
在这里插入图片描述

9.2 容器库概述(本节所有容器均适用)

在这里插入图片描述

对容器可以保存的元素类型的限制

  • 有些类没有提供默认构造函数,我们可以定义一个这种类型对象的容器,但我们在构造这种容器时不能只传递给它一个数目参数.
    在这里插入图片描述

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

9.2.1 迭代器

  • 与容器一样,迭代器有着公共的接口:如果一个迭代器提供某个操作,那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的.但是有一个例外:forward_list迭代器不支持递减运算符

迭代器范围

  • begin和end first和last(指向尾元素之后的元素)
    在这里插入图片描述

使用左闭合范围蕴含的编程假定

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

9.2.2 容器类型成员

  • 为了索引int的vector中的元素使用迭代器:vector<int>::iterator
  • 为了读取string的list中的元素:应该使用的类型是:list<string>::value_type
  • 为了写入数据,应该使用的类型是;list<string>::reference

9.2.3 begin和end成员

在这里插入图片描述

  • 不以c开头的函数都是被重载过的.也就是说,实际上有两个名为begin的成员,一个是const成员返回const_iterator,另外一个返回的是非常量成员iterator.当我们对一个非常量对象调用这些成元返回普通的.
    在这里插入图片描述

9.2.4 容器定义和初始化

在这里插入图片描述

将一个容器初始化为另外一个容器的拷贝

  • 将一个新容器创建为另外一个容器的拷贝的方法有两种:
    • 可以直接拷贝整个容器(除array)
    • 拷贝有一个迭代器对指定的范围
      在这里插入图片描述
    list<string> ls = {"1","2","3"};
    vector<const char *> vs = {"4","5","6"};

    list<string> list2(vs.begin(),vs.end());

在这里插入图片描述

列表初始化

与顺序容器大小相关的构造函数

在这里插入图片描述

标准库array具有固定大小

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

9.2.5 赋值和swap

在这里插入图片描述

使用assign(仅顺序容器)

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

9.2.6 容器大小操作

在这里插入图片描述

9.2.7 关系运算符

  • 除了无序关联容器外的所有容器都支持关系运算符.关系运算符左右两边的运算对象必须是相同的容器,且必须保存相同类型的元素.
  • 运算符的工作方式与string的关系运算类似.

容器的关系运算符使用元素的关系运算符完成比较

只有当其元素类型也定义了相应的比较运算符时,我们才可以使用关系运算符来比较两个容器

9.3 顺序容器操作(顺序容器特有操作)

9.3.1 向顺序容器添加元素

在这里插入图片描述

  • 在一个vector或string的尾部之外的任何位置,或是deque的首尾之外的任何位置添加元素都需要移动元素

使用push_back(除array和forward_list之外)

在这里插入图片描述

使用push_front

  • list,forward_list,deque支持
  • deque和vector提供随机访问元素的能力

在容器的特定位置添加元素(insert)

  • insert(iterator,element)

插入范围内元素

  • 传递的迭代器不能指向添加新元素的目标容器
  • 新标准之下,接受元素个数或范围的insert版本返回指向第一个新加入元素的迭代器

使用insert返回值

在这里插入图片描述

使用emplace操作

在这里插入图片描述
在这里插入图片描述
向一个vector,string,deque插入元素会使现有指向容器的迭代器,引用,指针生效.这时就应该结合insert返回的元素来进行操作

9.3.2 访问元素

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

访问成员函数返回的是引用

在这里插入图片描述

小标操作和安全的随机访问

  • 提供下标运算符的容器(string,vector,deque和arrate都提供下标运算符).
  • 如果我们希望确保下标是合法的,可以使用at成员函数.如果at下标越界,at会抛出一个out_of_range异常

9.3.3 删除元素

在这里插入图片描述

pop_front和pop_back成员函数

  • 与vector和string不支持push_front一样,这些类型也不支持pop_front
  • 不能对一个空容器执行1弹出操作
while(!ilist.empty()){
}

从容器内部删除一个元素(erase)

删除多个元素

slist.clear()
slist.erase(slist.begin(),slist.end())

在这里插入图片描述

int main()
{
    int a[] = {0,1,1,2,3,5,8,13,21,55,89};
    vector<int> vi ;
    list<int> li;
    vi.assign(a,a+11); // 将数组上的元素拷贝到vector中
    li.assign(a,a+11);

    vector<int>::iterator vit = vi.begin();

    while (vit != vi.end()){
        if(*vit %2 == 0){
            vit = vi.erase(vit);
        } else{
            vit++;
        }
    }

    vit = vi.begin();
    while (vit != vi.end()){
        cout<<*vit<<ends;
        vit++;
    }


    return 0;
}

9.3.4 特殊的forward_list操作

在这里插入图片描述

  • 由于forwar_list是一个单向列表,删除或者添加元素需要这个元素的前驱才能操作,但是在一个单链表中没有简单的方法获得一个元素的前驱节点,所以删除和添加元素操作都是通过改变给定元素之后的元素来完成的。
  • 由于这些操作与其他容器上的操作不同,forward_list并未定义insert,emplace,erase而是定义了insert_after,emplace_after,erase_after的操作。
    在这里插入图片描述
  • 当在forward_list中添加或删除元素时,我们必须关注两个迭代器,一个指向我们要处理的元素,另一个执行其前驱。

在这里插入图片描述

int main() {
    int a[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};
    forward_list<int> fi;
    fi.assign(a, a + 11); // 将数组上的元素拷贝到forward_list中

    int x1 = 21, x2 = 2; //查找x1并将x2插入到紧挨x1之后的位置

    forward_list<int>::iterator it = fi.before_begin();//返回第一个元素前面的迭代器
    forward_list<int>::iterator nestIt = fi.begin();//返回首元素

    it = fi.begin();
    while (it != fi.end()) {
        cout << *it << ends;
        it++;
    }
    it = fi.before_begin();
    cout<<endl;
    
    //查找x1
    while (nestIt != fi.end()) {
        if (*nestIt == x1) {
            fi.erase_after(it);  //删除it之后的元素,it在nextIt的前面
            break;
        } else {
            it++;
            nestIt++;
        }
    }

    it = fi.begin();
    while (it != fi.end()) {
        cout << *it << ends;
        it++;
    }

    nestIt = fi.begin();
    //插入x1到x2的位置
    while (nestIt != fi.end()) {
        if (*nestIt == x2) {
            fi.insert_after(nestIt, x1);
            break;
        } else {
            nestIt++;
        }
    }


    cout << endl;
    it = fi.begin();
    //插入x1到x2的位置
    while (it != fi.end()) {
        cout << *it << ends;
        it++;
    }
/*
 * 0 1 1 2 3 5 8 13 21 55 89
0 1 1 2 3 5 8 13 55 89
0 1 1 2 21 3 5 8 13 55 89
 */
    return 0;
}

9.3.5 改变容器大小(resize)

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

  • 对于元素是类类型,则单参数resize版本要求改类型必须提供一个默认构造函数。

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

  • 向容器中添加元素和从容器中删除元素的操作可能会使指向元素的指针,引用或者迭代器失效。而一个失效的指针,引用或迭代器将不再表示任何元素
    在这里插入图片描述
  • 容器是vector或者string的情况下,在向容器添加元素后,如果容器扩容,即容器的存储空间重新分配,则指向容器的迭代器失效
  • 容器是vector或者string的情况下,在向容器添加元素后,如果容器未扩容,则指向插入位置之前的元素的迭代器有效,但指向插入位置之后元素的迭代器将会失效,这是因为插入位置后的元素次序发生变化使得原本指向某元素的迭代器不再指向希望指向的元素。
  • 容器是deque的情况下,插入到任何位置都会导致迭代器。
  • 容器是list和forward_list的情况下,插入到任何位置,指向容器的迭代器仍然有效,
    在这里插入图片描述

编写改变容器的循环程序

在这里插入图片描述

  • insert在给定位置之插入新元素,然后返回指向新元素的迭代器,所以必须加两次,越过插入的新元素和正在处理的元素

不要保存end返回的迭代器

在这里插入图片描述
如果在一个循环中插入,删除deque或vector中的元素,不要缓存end返回的迭代器’
在这里插入图片描述
在这里插入图片描述

第一题:

  • list和forward_list与其他容器的一个不同是,迭代器不支持加减运算,因为链表中的元素并非在内存中联系存储,因此无法通过地址的加减在元素间远距离移动。因此,应多次调用++来实现与迭代器加法相同的效果。
  • list和forward_list支持++不支持+=`
    vector<int> vi = {0,1,2,3,4,5,6,7,8,9};

    auto iter = vi.begin();
    while(iter != vi.end())
    {
        if(*iter % 2)
        {
            iter = vi.insert(iter,*iter);
            iter+=2;
            cout<<1<<endl;
        }
        else
        {
            iter = vi.erase(iter); //删除之后返回我们删除的元素之后的元素
        }
    }
int main() {
    list<int> vi = {0,1,2,3,4,5,6,7,8,9};

    auto iter = vi.begin();
    while(iter != vi.end())
    {
        if(*iter % 2) //奇数
        {
            iter = vi.insert(iter,*iter);
            iter++;
            iter++;
        }
        else
        {
            iter = vi.erase(iter); //删除之后返回我们删除的元素之后的元素
        }
    }

    iter = vi.begin();
    while (iter != vi.end()){
        cout<<*iter<<ends;
        iter++;
    }
    return 0;
}
/删除奇数,复制偶数
int main() {
    
    //对于forward_list删除元素时,由于是单链表结构,需要维护前驱和后继两个迭代器
    forward_list<int> vi = {0,1,2,3,4,5,6,7,8,9};

    auto iter = vi.begin();
    auto prev = vi.before_begin();
    while(iter != vi.end())
    {
        if(*iter % 2) //奇数
        {
            iter = vi.insert_after(iter,*iter); //返回插入的元素
            prev = iter;
            iter++;
        }
        else
        {
            iter = vi.erase_after(prev); //删除之后返回我们删除的元素之后的元素
        }
    }

    iter = vi.begin();
    while (iter != vi.end()){
        cout<<*iter<<ends;
        iter++;
    }
    return 0;
}

第二题

  • 编译器处理形参的顺序可能是不同的,由右向左或者有左向右都有可能。

9.4 vector对象是如何增长的

管理容量的成员函数

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

capacity和size

  • capacity是在不分配内存空间的前提下它最多可以保存多少元素,size是指它已经保存的元素的数目。
  • 实际上只要没有操作需求超过vector的容量,vector就不能重新分配内存空间

9.5 额外的string操作

9.5.1 构造string的其他方法

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

substr操作

在这里插入图片描述

习题

在这里插入图片描述

9.5.2 改变string的其他方法

在这里插入图片描述

append和replace函数

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

改变string的多种重载函数

在这里插入图片描述

void test(string &s, string& oldVal, string& newVal)
{
	if (!s.size())
		return; //s为空
	string::iterator its = s.begin();
	int j = 0; //记录正在遍历的s的位置
	while (its != s.end()) {

		if (*its == oldVal[0] && j < s.size())
		{
			cout << "找到首元素" << endl;
			string::iterator oldIt = oldVal.begin();
			while (oldIt !=oldVal.end() && *its == *oldIt && j< s.size())
			{
				oldIt++;
				its++;
			}
			if (oldIt == oldVal.end())
			{ //s中有oldval并找到其位置
				cout << "找到了" << endl;
				s.erase(j,oldVal.size());
				s.insert(j, newVal);
				break;
			}
		
		}
		else
		{
			its++;
			j++;
		}
	
	}
}
int main(int argc, char** argv)
{
	string s = "newtho";
	string old = "tho";
	string news = "news";
	test(s, old, news);
	cout << s << endl;   //newsnew
	return 0;
}

9.5.3 string搜索操作

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

指定在哪里开始搜索

在字符串中循环的搜索字符串出现的所有位置


void test(string &s, string& findStr)
{
	string::size_type pos = 0;

	while ((pos = s.find_first_of(findStr,pos)) != string::npos)
	{
		cout << "pos = " << pos<<"Element is " << s[pos]<< endl;
		++pos;
	}
}

s.find_first_of(str)查找的是str中的任意一个字符在s首次出现的位置

逆向搜索

rfind

习题

for-each语句遍历string会乱码

string::size_type pos = 0;
	string  str = "qwertyuiopasdfghjklzxcvbnm";
	string::size_type len = str.size();
	 for(int i =0;i< len;i++)
	 {	
		 str += toupper(str[i]);
		 cout << str[i] << "  " << toupper(str[i]) << " " << str << endl;
		 
	 }
	 cout << str << endl;

9.5.4 compare函数

在这里插入图片描述

9.5.5 数值转换

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

9.5 容器适配器

在这里插入图片描述

定义一个适配器

在这里插入图片描述

栈适配器

在这里插入图片描述

队列适配器

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL进阶SQL语句(二)

MySQL进阶SQL语句&#xff08;二&#xff09; 一、MySQL进阶SQL语句1.1 连接查询1.2 CREATE VIEW视图&#xff0c;可以被当作是虚拟表或存储查询1.3 UNION 联集1.4 CASE1.5 空值(NULL) 和 无值() 的区别1.6 正则表达式 二、存储过程2.1 存储过程定义2.2 存储过程的优点2.3 存储…

(秋招)闭环检测流程回顾

vins中的闭环检测和重定位 回环检测的关键就是如何有效检测出相机曾经经过同一个地方&#xff0c;这样可以避免较大的累积误差&#xff0c;使得当前帧和之前的某一帧迅速建立约束&#xff0c;形成新的较小的累积误差。由于回环检测提供了当前数据与所有历史数据的关联&#xf…

快速搭建node.js新项目和大事件后台项目

声明&#xff1a;参考https://zhuanlan.zhihu.com/p/464271490?utm_id0 参考&#xff1a;https://brucecai55520.gitee.io/bruceblog/notes/nodejs/ev_api_server.html#_1-4-%E5%88%9D%E5%A7%8B%E5%8C%96%E8%B7%AF%E7%94%B1%E7%9B%B8%E5%85%B3%E7%9A%84%E6%96%87%E4%BB%B6%E5…

Linux文件系统的缓冲区问题

目录 一.什么是缓冲区&#xff1f; 1.1实验案例1&#xff1a; 情况1&#xff1a;运行该程序 情况2&#xff1a;此时我将该程序运行的结果输出重定向到一个文本文件中&#xff1a; 二.为什么要有缓冲区&#xff1f; 于是引出了缓冲区的刷新策略&#xff1a; 三.缓冲区在哪…

【学习笔记】 科目一之计算题篇

【学习笔记】 科目一之计算题篇 三点估算PERT 三点估算期望:(悲观+4*最可能+乐观)/6三点估算标准差:(悲观-乐观)/6正态分布四个数:34.1%,13.65%,2.1%,0.15%决策树 分叉计算注意:成本越小越好投资回报:收益-投入投资回报率(ROI)=收益-投入/投入投资回收期 静态回…

算法--PageRank

概念 PageRank是Google提出的算法&#xff0c;用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度。是Google创始人拉里佩奇和谢尔盖布林于1997年创造的PageRank实现了将链接价值概念作为排名因素。 GOOGLE PageRank并不是唯一的链接相关的排名算法&#xff0c;而…

如何提升 MySQL 的查询速度?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言优化数据库结构1 使…

QT(一) 安装 QT(二)

第一章 &#xff1a; Qt 安装 下载地址安装 打开 cmd 运行镜像 &#xff1a; qt-unified-windows-x64-4.6.0-online.exe --mirror https://mirrors.aliyun.com/qt Hello 因为是qmake 所以是.proCtrl R 直接运行 第二章 GUI程序设计基础 main文件 *.ui : 有UI设计器自动生成…

【工具】Spring 历史官方文档理解(持续更新)

文章目录 [1] Spring Framework 5.2.24CoreAOP 概念AspectJoin pointAdvicePointcutIntroductionTarget objectAOP proxyWeaving Spring AOPAspectJ官方 demo 学习 Pointcut 表达式官方 demo 学习 Advice 声明官方 demo 学习 Introductions &#xff08;接口拓展&#xff09;AO…

0004Java程序设计-SSM+JSP医院挂号系统

摘 要 医院挂号&#xff0c;一直以来就是困扰医院提高服务水平的重要环节&#xff0c;特别是医疗水平高、门诊访问量高的综合型医院&#xff0c;门诊拥挤就成了普遍现象。因此&#xff0c;本文提出了医院挂号系统。预约挂号&#xff0c;是借助信息化的技术&#xff0c;面向全社…

代码随想录二刷 day32 | 贪心之 122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II

这里写目录标题 122.买卖股票的最佳时机II55. 跳跃游戏45.跳跃游戏II 122.买卖股票的最佳时机II 题目链接 解题思路&#xff1a; 首先要清楚两点&#xff1a; 只有一只股票&#xff01;当前只有买股票或者卖股票的操作 想获得利润至少要两天为一个交易单元。 代码如下&#x…

【Unity每日一记】时间Time类-做时间管理大师

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

独立开发变现周刊(第92期):创建一个年收入350万美元的小工具,1000万至1500万美元出售...

分享独立开发、产品变现相关内容&#xff0c;每周五发布。 目录 1、Vercel AI: 使用React, Svelte和Vue快速构建 AI 驱动的应用2、Novel&#xff1a;AI自动补全功能的Notion风格所见即所得编辑器3、Notionbase: 通过Notion轻松建立你的AI聊天机器人4、Plasmo: 一款功能强大的浏…

Python入门教程+项目实战-14.1节-程序实战-二分查找算法

目录 14.1.1 理解函数类型 14.1.2 函数的定义 14.1.3 函数的形参&#xff0c;实参&#xff0c;以及调用 14.1.4 函数的返回值 14.1.5 函数的命名规范 14.1.6 知识要点 14.1.7 系统学习python 14.1.1 理解函数类型 在Python中&#xff0c;函数也是一种数据类型。在理解函…

C++——详解类模板与友元函数

纵有疾风起&#xff0c;人生不言弃。本文篇幅较长&#xff0c;如有错误请不吝赐教&#xff0c;感谢支持。 &#x1f4ac;文章目录 类模板与友元函数1️⃣非模板友元函数2️⃣约束模板友元函数3️⃣非约束模板友元函数 类模板与友元函数 模板类的友元函数有三类&#xff1a; …

Qt/C++编写手机版本视频播放器和Onvif工具(可云台和录像)

一、前言 用Qtffmpeg写播放器很多人有疑问&#xff0c;为何不用Qt自己的多媒体框架来写&#xff0c;最重要的原因是Qt自带的目前都依赖具体的本地解码器&#xff0c;如果解码器不支持&#xff0c;那就是歇菜的&#xff0c;最多支持个MP4格式&#xff0c;而且在手机上也都是支持…

C国演义 [第七章]

第七章 最长重复子数组题目理解步骤dp含义递推公式初始化为啥dp数组如此奇怪 遍历顺序 代码 最长公共子序列题目理解步骤dp含义递推公式初始化遍历顺序 代码 总结 最长重复子数组 力扣链接 给两个整数数组 nums1 和 nums2 &#xff0c;返回 两个数组中 公共的 、长度最长的子…

设计模式之中介者模式笔记

设计模式之中介者模式笔记 说明Mediator(中介者)目录中介者模式示例类图抽象中介者类抽象同事类租房者类房主类具体的中介者角色类测试类 说明 记录下学习设计模式-中介者模式的写法。JDK使用版本为1.8版本。 Mediator(中介者) 意图:用一个中介对象来封装一系列的对象交互。…

剑指 Offer 68 - II. 二叉树的最近公共祖先 / LeetCode 236. 二叉树的最近公共祖先(搜索与回溯)

题目&#xff1a; 链接&#xff1a;剑指 Offer 68 - II. 二叉树的最近公共祖先&#xff1b;LeetCode 236. 二叉树的最近公共祖先 难度&#xff1a;中等 上一题博客&#xff1a;剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 / LeetCode 235. 二叉搜索树的最近公共祖先&#xf…

python:并发编程(二十四)

前言 本文将和大家一起探讨python并发编程的实际项目&#xff1a;win图形界面应用&#xff08;篇六&#xff0c;共八篇&#xff09;&#xff0c;系列文章将会从零开始构建项目&#xff0c;并逐渐完善项目&#xff0c;最终将项目打造成适用于高并发场景的应用。 本文为python并…