C++20 STL CookBook 7 Containers(II)

让vector在插入删除的时候仍然保证是有序的

首先,STL的确提供了一种办法来检查我们的目标容器是不是有序的:std::is_sorted - cppreference.com,也就是std::is_sorted。我们当然可以这样做:

#include <iostream>
#include <vector>
#include <algorithm>
int main() {std::vector v{ 1, 4, 3 };if (std::is_sorted(v.begin(), v.end())) {std::cout << "Vector is sorted\n";}else {std::cout << "Vector is not sorted\n";}std::sort(v.begin(), v.end());if (std::is_sorted(v.begin(), v.end())) {std::cout << "Vector is sorted\n";}else {std::cout << "Vector is not sorted\n";}return 0;
}

结果显而易见:

Vector is not sorted
Vector is sorted

当然还可以添加谓词,这里就不再赘述了

我们现在关心的是:如果我们向元素中插入一个新元素(删除如何呢?想一想我们有必要考虑删除的case吗?),我们能不能保证原来的数组还是有序的呢?

答案是,可以做到,但是我们需要组合我们的STL算法完成这个工作!

template<typename C, typename E>
void insert_sorted(C& c, const E& e) {const auto pos{ std::ranges::lower_bound(c, e) };c.insert(pos, e);
}

这个算法有一定的通用局限性:这是因为std::sort() 算法(及其派生算法)需要支持随机访问的容器。并非所有 STL 容器都满足此要求(std::list是位列其中的)

高效地将元素插入到映射中

映射类Map是一个关联容器,它包含键值对,其中键在容器内必须是唯一的。这里有多种方法可以填充映射容器。

map<string, string> m;

嗯哼,这就是说我们的Key和Value都是字符串,字符串之间的映射。一般的,我们喜欢使用 [] 运算符添加元素:

m["Miles"] = "Trumpet"

或者使用 insert() 成员函数:

m.insert(pair<string,string>("Hendrix", "Guitar"));

还可以使用 emplace() 成员函数:

m.emplace("Krupa", "Drums");

笔者倾向于使用 emplace() 函数。在 C++11 中引入的 emplace() 使用完美转发来为容器放置(就地创建)新元素。参数直接转发到元素构造函数。这快速、高效且易于编码。

虽然它肯定比其他选项有所改进,但 emplace() 的问题在于,即使不需要,它也会构造一个对象。这涉及调用构造函数、分配内存和移动数据,然后丢弃该临时对象。为了解决这个问题,C++17 提供了新的 try_emplace() 函数,该函数仅在需要时构造值对象。这对于大型对象或许多位置尤其重要

映射的每个元素都是一个键值对。在对结构中,元素被命名为第一和第二,但它们在映射中的目的是键和值。我倾向于将值对象视为有效载荷,因为这通常是映射的要点。要搜索现有键,try_emplace() 函数必须构造键对象;这是无法避免的。但它不需要构造有效载荷对象,除非需要将其插入到映射中。

高效的修改map中的keys

映射是一种存储键值对的关联容器。容器按键排序。键必须是唯一的,并且是 const 限定的,因此不能更改。例如,如果我填充映射并尝试更改键,则会在编译时收到错误:

std::map<int, string> this_map {{1, "foo"}, {2, "bar"}, {3, "baz"}
};
​
auto wanna_change = this_map.begin();
wanna_change->first = 114514;

如果您需要重新排序地图容器,可以使用extract() 方法交换键来实现。作为 C++17 的新增功能,extract() 是地图类及其派生类中的成员函数。它允许从序列中提取地图的元素,而无需触及有效负载。提取后,键不再是 const 限定的,可能会被修改。

下面,我们来演示一下这个extract方法应该如何使用!

using SpecialMap = std::map<int, std::string>;
void printMap(const SpecialMap& m){std::cout << "Maps are here:> \n";for(const auto& [aInt, aString] : m){std::print("{} : {}\n", aInt, aString);}
}

现在您可以测试一下好不好用这个函数。

SpecialMap aMap {{1, "Charlie"}, {2, "Chen"}, {3, "Qt"}, {4, "C++"}, {5, "Idk what should e be at here:("}
};
printMap(aMap);

下面才是正文,我们交换map两个键值对的key:

template<typename Map, typename Key>
bool swap_key(Map& m, const Key& key1, const Key& key2)
{
// 取出我们的auto node1 = m.extract(key1);auto node2 = m.extract(key2);if (!node1 ||!node2){return false;}swap(node1.key(), node2.key());m.insert(std::move(node2));m.insert(std::move(node1));return true;
}

小小的测试一下:

使用带有自定义键的 unordered_map

对于有序映射,键的类型必须是可排序的,这意味着它必须至少支持小于 < 比较运算符。假设您想要使用具有不可排序的自定义类型的关联容器。例如,向量 (0, 1) 不小于或大于 (1, 0),它只是指向不同的方向。在这种情况下,您仍然可以使用 unordered_map 类型。让我们看看如何做到这一点。

我们现在呢,把Key设置为一个坐标:

struct Position {int x{};int y{};friend bool operator==(const Position& lhs, const Position& rhs){return lhs.x == rhs.x && lhs.y == rhs.y;}
};
​
using PositionMap = std::unordered_map<Position, int>;

我们知道unordered_map还需要第三个模板参数:

template<class Key,class T,class Hash = std::hash<Key>,class KeyEqual = std::equal_to<Key>,class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;

所以,实际上我们还需要提供将Key映射为哈希值的办法。

所以我们需要重载一下...

namespace std {template<>struct hash<Coord> {size_t operator()(const Coord& c) const {return static_cast<size_t>(c.x)+ static_cast<size_t>(c.y);}};
}

现在我们就可以这样使用我们的Map With self defined Key了。

void printMap(const PositionMap& positionMap)
{for (const auto& [position, value] : positionMap) {std::print("({}, {}) = {}\n", position.x, position.y, value);}
}

使用set来unique我们的输入

集合容器是一种关联容器,其中每个元素都是一个值,用作键。集合中的元素按排序顺序维护,不允许重复的键。集合容器经常被误解,与更通用的容器(例如向量和映射)相比,它的用途更少且更具体。集合的一个常见用途是从一组值中过滤重复项。

作为示例,我们将从标准输入中读取单词并过滤掉重复项。

我们首先为 istream 迭代器定义一个别名。我们将使用它从命令行获取输入。

using input_it = istream_iterator<string>;

在 main() 函数中,我们将为我们的单词定义一个集合:

int main() {
set<string> words;

该集合定义为一组字符串元素。我们定义一对迭代器以与 inserter() 函数一起使用:

input_it it{ cin };
input_it end{};

end 迭代器用其默认构造函数初始化。这称为流结束迭代器。当我们的输入结束时,此迭代器将与 cin 迭代器进行比较。inserter() 函数用于将元素插入到集合容器中:

copy(it, end, inserter(words, words.end()));

我们使用 std::copy() 方便地从输入流中复制单词。现在我们可以打印出我们的集合来查看结果:

for(const string & w : words) {cout << format("{} ", w);
}
cout << '\n';

我们可以通过将一堆单词传送到其输入来运行该程序:

➜  echo "a a b b b c c c c hello world hello" | .\Modules.exe
a
b
c
hello
world

现在我们看:该集合已消除重复项并保留了插入的单词的排序列表。

集合容器是核心。它仅包含唯一元素。当您插入重复项时,该插入将失败。因此,您最终会得到每个唯一元素的排序列表。但这不是此配方唯一有趣的部分。istream_iterator 是一个从流中读取对象的输入迭代器。我们像这样实例化输入迭代器:

istream_iterator<string> it{ cin };

现在我们有一个来自 cin 流的字符串类型的输入迭代器。每次我们取消引用此迭代器时,它都会从输入流中返回一个单词。

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

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

相关文章

二叉树搜索树(下)

二叉树搜索树&#xff08;下&#xff09; 二叉搜索树key和key/value使用场景 key搜索场景 只有key作为关键码&#xff0c;结构中只需要存储key即可&#xff0c;关键码即为需要搜索到的值&#xff0c;搜索场景只需要判断 key在不在。key的搜索场景实现的二叉树搜索树支持增删查…

人力资源招聘系统-提升招聘效率与质量的关键工具

在当今这个竞争激烈的商业环境中&#xff0c;企业要想在市场中立于不败之地&#xff0c;关键在于拥有高素质的人才队伍。然而&#xff0c;传统的招聘方式往往效率低下&#xff0c;难以精准匹配企业需求与人才特质&#xff0c;这无疑给企业的发展带来了不小的挑战。 随着科技的飞…

【C++】类中的“默认成员函数“--构造、析构、赋值

目录 概念引入&#xff1a; 一、构造函数 问题引入&#xff1a; 1&#xff09;构造函数的概念 2&#xff09;构造函数的特性 二、析构函数 1&#xff09;析构函数概念 2&#xff09;析构函数特性 三、拷贝构造函数 1)拷贝构造函数概念 示例代码&#xff1a; 2)深拷…

环丙烷环辛炔聚乙二醇磷脂,淡黄色固体,BCN-PEG-DSPE

中文名称&#xff1a;环丙烷环辛炔聚乙二醇磷脂 英文名称&#xff1a;BCN-PEG-DSPE 外观&#xff1a;通常为黄色或淡黄色固体 材料来源&#xff1a;为华生物 溶解性&#xff1a;在有机溶剂&#xff08;如氯仿、乙醇&#xff09;中具有良好的溶解性&#xff0c;而在水中的溶…

202409电子学会青少年机器人技术等级考试(六级)理论综合真题

青少年机器人技术等级考试理论综合试卷&#xff08;六级&#xff09; 分数&#xff1a; 100 题数&#xff1a; 30 一、 单选题(共 20 题&#xff0c; 共 80 分) 1. 使用 ESP32 for Arduino SPI 类库&#xff0c; 下列选项中&#xff0c; 具有设置时钟模式功能的成员函数是&…

如何学习VBA_3.2.14:字符串的处理

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的劳动效率&#xff0c;而且可以提高数据处理的准确度。我推出的VBA系列教程共九套和一部VBA汉英手册&#xff0c;现在已经全部完成&#xff0c;希望大家利用、学习。 如果…

ABeam News | ABeam中国受邀参加2024中国知识管理年会暨第14届China MIKE颁奖典礼,并荣获大奖

“ABeam/ News ” 近日&#xff0c;2024中国知识管理年会暨第14届China MIKE颁奖典礼圆满召开&#xff0c;大会结合AI赋能新质生产力的热点话题&#xff0c;以“AI超能力KM新价值” 作为主题&#xff0c;为与会观众带来知识管理的一场盛宴。ABeam中国受邀参会并荣获2024 China…

Error: Could not find or load main class org.apache.catalina.startup.Bootstrap

#现象&#xff1a; 官网下载tomcat source包后&#xff0c;启动报错&#xff0c;等一系列缺包造成服务无法启动 Error: Could not find or load main class org.apache.catalina.startup.Bootstrapjava.lang.ClassNotFoundException: org.apache.juli.logging.LogFactory原因 …

论文解读《CTRLsum: Towards Generic Controllable Text Summarization》

引言&#xff1a;一篇上交大佬的著作 ✅ NLP 研 2 选手的学习笔记 笔者简介&#xff1a;Wang Linyong&#xff0c;NPU&#xff0c;2023级&#xff0c;计算机技术 研究方向&#xff1a;文本生成、大语言模型 论文链接&#xff1a;https://aclanthology.org/2022.emnlp-main.396.…

【spotfire】脚本相关

文章目录 ironpython脚本使用JS实现弹出窗口思路实现效果 脚本的使用可以极大扩展spotfire的功能&#xff0c;但如何使用脚本一直不得其门而入&#xff0c;咨询厂商、查询资料&#xff0c;特此记录备忘。 ironpython脚本使用 参见官网教程&#xff1b; 部分参考资料如下&#…

嵌入式硬件杂谈(一)-推挽 开漏 高阻态 上拉电阻

引言&#xff1a;对于嵌入式硬件这个庞大的知识体系而言&#xff0c;太多离散的知识点很容易疏漏&#xff0c;因此对于这些容易忘记甚至不明白的知识点做成一个梳理&#xff0c;供大家参考以及学习&#xff0c;本文主要针对推挽、开漏、高阻态、上拉电阻这些知识点的学习。 目…

RCAgent:云故障根因分析的自主智能体工具增强型大模型

人工智能咨询培训老师叶梓 转载标明出处 由于云上计算部署的不断扩展&#xff0c;手动在线异常RCA工作流程&#xff0c;如创建故障排除工具&#xff0c;常常使网站可靠性工程师&#xff08;SRE&#xff09;应接不暇。为了提高云服务可靠性效率&#xff0c;一系列人工智能运维&…

PET-文件包含-FINISHED

include发生错误报warning&#xff0c;继续执行。require发生错误直接error&#xff0c;不继续执行 无视扩展名&#xff0c;只要能解析&#xff0c;就能当可执行文件执行&#xff0c;哪怕文件后缀或没后缀 1 条件竞争 pass17 只需要知道tmp的路径。把xieshell.jpg上传&…

基于Java+SpringBoot+Vue前后端分离课程管理系统

一、作品包含 源码数据库设计文档全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据库&…

学术界的秘密武器:Zotero7大插件推荐

还在为海量文献管理头疼吗?还在为找不到合适的插件犯愁吗?别急,今天我就要带你解锁Zotero的终极武器 - 那些让你爱不释手的必备插件! 作为一个从小白到文献管理达人的过来人,我可以负责任地说:没有这些插件,你的Zotero只能发挥一半功力!安装了这些插件,你的效率绝对能飙升! …

Linux·进程信号

信号是一种用户、OS、其他进程&#xff0c;向目标进程发送异步事件的一种方式。 在系统中信号是OS出场时程序员就内置好了的&#xff0c;因此任何进程都认识所有信号&#xff0c;信号产生之前&#xff0c;信号的处理方案就已经设定好了&#xff0c;一般有三种 1. 默认行为 2.…

BizDevOps:从理念到实践,贯通企业全链路协同

&#x1f446; 点击蓝字 关注我们 引言 BizDevOps的概念由DevOps发展和进化而来&#xff0c;其目标超越了开发和运维的协同&#xff0c;进一步实现业务、研发和运维的全链条协作&#xff0c;让业务作为价值的起点及核心目标。 BizDevOps的核心驱动力在于解决效率和正确性上的割…

工厂方法模式和抽象工厂模式

序 本文主要是记录学习设计模式当中的工厂方法和抽象工厂时碰到的疑惑和对答案的探讨 刚接触时的工厂方法模式和抽象工厂模式 工厂方法模式 类图 代码 //工厂public interface TVFactory {TV produce(); }public class TclTVFactory implements TVFactory{Overridepublic T…

NVR小程序接入平台EasyNVR多品牌NVR管理工具/设备:RTMP协议摄像头的接入

随着安防技术的不断进步&#xff0c;越来越多的摄像头开始支持RTMP&#xff08;Real Time Messaging Protocol&#xff09;协议&#xff0c;这种协议使得视频流的实时传输和分发变得更加高效和便捷。NVR小程序接入平台EasyNVR作为一款功能强大的流媒体服务器&#xff0c;支持多…

硬件基础20 数模转换器D/A DAC

目录 一、DAC基本原理 二、倒T形电阻网络D/A转换器 三、权电流型D/A转换器 四、重要技术指标与参数 1、分辨率/位数 2、转换精度 &#xff08;1&#xff09;、比例系数误差 &#xff08;2&#xff09;、失调误差 3、转换速度 4、温度系数 五、DAC的应用 1、数字式可…