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 流的字符串类型的输入迭代器。每次我们取消引用此迭代器时,它都会从输入流中返回一个单词。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FlinkSql读取kafka数据流的方法(scala)

我的scala版本为2.12 <scala.binary.version>2.12</scala.binary.version> 我的Flink版本为1.13.6 <flink.version>1.13.6</flink.version> FlinkSql读取kafka数据流需要如下依赖&#xff1a; <dependency><groupId>org.apache.flink&…

语音 AI 革命:未来,消费者更可能倾向于与 AI 沟通,而非人工客服

「未来&#xff0c;消费者更可能倾向于与 AI 沟通&#xff0c;而非人工客服&#xff0c;因为这将成为解决问题的最高效途径。」 这篇来自 Bessemer Venture Partners 的报告&#xff0c;是目前为止对语音 AI 在企业应用上最完整清晰的一次梳理。 核心要点&#xff1a; 尽管市…

【t365】基于springboot的高校疫情防控系统

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差&#x…

DAY27|贪心算法Part01|LeetCode:455.分发饼干、376. 摆动序列、53. 最大子序和

贪心算法 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 贪心算法并没有固定的套路&#xff0c;最难想的就在于如何通过局部最优去推出全局最优。在做一个题目的时候&#xff0c;靠自己手动模拟&#xff0c;如果模拟可行&#xff0c;就可以试一试贪心策略…

四万字长文SpringBoot、Spring、SpringMVC等相关面试题(注:该篇博客将会持续维护 最新维护时间:2024年11月12日)

&#x1f9f8;本篇博客重在讲解SpringBoot、Spring、SpringMVC等相关面试题&#xff0c;将会实时更新&#xff0c;欢迎大家添加作者文末联系方式交流 &#x1f4dc;JAVA面试题专栏&#xff1a;JAVA崭新面试题——2024版_dream_ready的博客-CSDN博客 &#x1f4dc;作者首页&…

免费HTML模板和CSS样式网站汇总

HTML模板&#xff1a;&#xff08;注意版权&#xff0c;部分不可商用&#xff09; 1、Tooplate&#xff0c;免费HTML模板下载 Download 60 Free HTML Templates for your websitesDownload 60 free HTML website templates or responsive Bootstrap templates instantly from T…

深入理解接口测试:实用指南与最佳实践5.0(二)

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

SpringBoot技术:共享汽车行业的新动力

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了共享汽车管理系统的开发全过程。通过分析共享汽车管理系统管理的不足&#xff0c;创建了一个计算机管理共享汽车管理系统的方案。文章介绍了共享汽车管理系统的系…

Java Review - 线程池原理源码解析

文章目录 Pre为什么要用线程池线程池的优点&#xff08;1&#xff09;重复利用线程&#xff08;2&#xff09;控制线程的数量 线程池实现原理线程池ThreadPoolExecutor类关系线程池的工作流程任务队列空闲线程的存活时间参数ThreadFactory拒绝策略被拒绝后的任务如何再次执行 向…

昇思大模型平台打卡体验活动:项目4基于MindSpore实现Roberta模型Prompt Tuning

基于MindNLP的Roberta模型Prompt Tuning 本文档介绍了如何基于MindNLP进行Roberta模型的Prompt Tuning&#xff0c;主要用于GLUE基准数据集的微调。本文提供了完整的代码示例以及详细的步骤说明&#xff0c;便于理解和复现实验。 环境配置 在运行此代码前&#xff0c;请确保…

【MySQL】数据库表连接简明解释

未经许可,不得转载。 文章目录 表连接表连接的类型内连接与外连接结合 WHERE 条件交叉连接(cross join)表连接 在关系型数据库中,建模是数据组织的核心难点。数据库建模需要将数据关系理清,构建出适合存储和查询的结构。 所谓“模型”包括实体(entity) 和关系(relati…

离线安装GDAL与MapServer:在银河麒麟V10上的快速指南

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 ✨特色专栏&#xff1a…

17.UE5丰富怪物、结构体、数据表、构造函数

2-19 丰富怪物&#xff0c;结构体、数据表格、构造函数_哔哩哔哩_bilibili 目录 1.结构体和数据表格 2.在构造函数中初始化怪物 3.实现怪物是否游荡 1.结构体和数据表格 创建蓝图&#xff1a;结构体蓝图 在结构体蓝图中添加变量&#xff0c;如下所示&#xff0c;为了实现不…

Kafka 快速入门(一)

1.1安装部署 1.1.1 集群规划 bigdata01bigdata02bigdata03zookeeperzookeeperzookeeperkafkakafkakafka 1.1.2 集群部署 官方下载地址&#xff1a;http://kafka.apache.org/downloads.html 检查三台虚拟机的zk是否启动&#xff1a;zkServer.sh start 默认启动方式 1)解压…

零件图纸的技术要求及标注

1零件的技术要求 零件在加工、检验时的各项技术要求&#xff0c;通常是指表面粗糙度、尺寸公差、形状和位置公差&#xff0c;材料的热处理及表面处理等。 2尺寸公差与配合 1、零件的互换性&定义、作用 在按规定要求大量制造的零件或部件中&#xff0c;任取一个&#xff0…

Python 的 Pygame 库,编写简单的 Flappy Bird 游戏

Pygame 是一个用 Python 编写的开源游戏开发框架&#xff0c;专门用于编写 2D 游戏。它提供了丰富的工具和功能&#xff0c;使得开发者能够快速实现游戏中的图形渲染、声音播放、输入处理和动画效果等功能。Pygame 非常适合初学者和想要快速创建游戏原型的开发者。 Pygame 的主…

【缓存策略】你知道 Cache Aside(缓存旁路)这个缓存策略吗

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

2024版最新kali linux 新手教程(非常详细)零基础入门到精通,收藏这篇就够了

您是否有兴趣使用 Kali Linux&#xff0c;但不知道从哪里开始&#xff1f;您来对地方了。 Kali Linux 是一个强大的渗透测试和道德黑客工具&#xff0c;提供许多工具和资源。 本 Kali Linux 教程将向您展示如何下载和安装它、解释桌面并强调您应该知道的关键领域。接下来&…

Android JNI 技术入门指南

引言 在Android开发中&#xff0c;Java是一种主要的编程语言&#xff0c;然而&#xff0c;对于一些性能要求较高的场景&#xff08;如音视频处理、图像处理、计算密集型任务等&#xff09;&#xff0c;我们可能需要使用到C或C等语言来编写底层的高效代码。为了实现Java代码与C…

国标GB28181视频平台EasyCVR私有化部署视频平台对接监控录像机NVR时,录像机“资源不足”是什么原因?

EasyCVR视频融合云平台&#xff0c;是TSINGSEE青犀视频“云边端”架构体系中的“云平台”系列之一&#xff0c;是一款针对大中型项目设计的跨区域、网络化、视频监控综合管理系统平台&#xff0c;通过接入视频监控设备及视频平台&#xff0c;实现视频数据的集中汇聚、融合管理、…