C++相关概念和易错语法(23)(set、仿函数的应用、pair、multiset)
1.set和map存在的意义
(1)set和map的底层都是二叉搜索树,可以达到快速排序(当我们按照迭代器的顺序来遍历set和map,其实是按照中序来遍历的,是排过序的)、去重、搜索的目的。
(2)优先级队列priority_queue也有类似的功能,但是它的底层是数组,在插入删除频繁的情况下效率降低,且它的数据结构是堆,在排序上效率还行,但在搜索上就无能为力了。
(3)在C++数据结构重要知识点(1)我就讲过二叉搜索树的特性,在退化的情况下搜索效率低下,所以要引入AVL树、红黑树这样的平衡树来解决问题。set和map就引入了红黑树,使得这两个容器的搜索效率很高。
(4)set和map有什么区别呢?其实就是分别对应key和key-value模型。set是针对key单个数据的二叉搜索树,而map是针对key-value那样的键值对的二叉搜索树。
(5)两种容器
序列式容器:vector、list对存储数据的顺序的要求不高,注意这句话的意思是在序列式容器中换两个数据虽然可能会影响到它的功能(比如本来是降序排列的vector,现在被打乱了),但不影响容器结构本身,vector还叫vector
关联式容器:map、set对数据顺序有强关联性,结构靠数据支撑,如果你随便换两个数据的位置,那么整个容器就崩了,而且无法修复。
2.set
set的底层引入了红黑树,大致和key模型的二叉搜索树一样,是借助二叉树的特性来存放数据,达到排序和搜索的功能的。但是在接口上和我们上篇文章分享的又不一样
(1)模板参数、仿函数的应用
第一个模板参数:要存放数据的类型,可以是int这样的内置类型,也可以是自定义类型
第三个模板参数基本不用管
第二个模板参数:默认是less<T>,在用迭代器遍历时是从小到大,注意我们前面讲的优先级队列priority_queue默认也是less<T>,但对应的是大堆。我们也可以自己写一个仿函数作为set的第二个模板参数,自定义规则,不过自定义仿函数的坑有点多,下面分享一下需要注意的点,加深对仿函数的理解。
先看以下代码
#include <iostream>
#include <string>
#include <set>
using namespace std;template<class T>
struct Compare
{bool operator()(const T& t1, const T& t2) const{return t1 > t2;}
};template<>
struct Compare<string>
{bool operator()(const string& s1, const string& s2) const{return (s1.size() > s2.size()) || (s1.size() == s2.size() && s1 < s2);}
};int main()
{set<int, Compare<int>> s1;s1.insert(1);s1.insert(2);s1.insert(3);set<string, Compare<string>> s2;s2.insert("zzzzzzz");s2.insert("aaaaaaa");s2.insert("bb");for (const auto& e : s1){cout << e << " ";}cout << endl;for (const auto& e : s2){cout << e << " ";}return 0;
}
输出结果是
为什么对于s1是从大排到小呢?为什么s2是这样排的呢?它们是怎样控制的呢?
在默认的情况下是less,对应的是从小排到大,即小的元素在大的元素前面,因此我们可以这样分析
再分析我们的
在写仿函数的时候特别注意举一反三,我上面两张图都提到的“返回true是谁在前”并不适用于所有情况(map和set都遵循),返回true时到底是t1在前还是t2在前要自己判断。借助默认排序方式和仿函数类型可以判断,如果set默认仿函数是greater,而默认访问是从小到大,那么自己写仿函数时就应该遵循“返回true时是t2(第二个函数参数)在前”来写代码了。
我们并不知道STL里面到底是怎样排序的,所以从细节推理出排序结果很重要,看似很简单,但一定不能含糊。
还有个细节:在自己写仿函数时要把重载函数定义为const对象,否则是编译不通过的。
(2)构造函数
总体分为三类:空构造、拷贝构造、迭代器构造
最后的内存池相关的参数不管它,倒数第二个comp只能是显式实例化容器时使用的仿函数,不过一般也不写,因为编译器会自己生成对应的仿函数
(3)insert、pair
insert最常用的就是第一个,第二第三个基本不用。但是返回值pair<iterator, bool>是什么呢?
pair是一个模板类,叫键值对,它有两个成员变量,一个叫first,另一个叫second,first和second构成一一对应的关系,first相当于key,second相当于value,在map中也用到了它。
要创建一个pair对象也很简单
pair和我们之前学的容器不同,pair只是一个存储数据的类型,它的底层非常简单,它存在的意义就是将key和value联系起来,根本不存在增删查改。
作为一个专门用于存储数据的类型,它也有自己的判断大小的方式,也很好理解。当first和second都相同时pair相同,first大的pair就大,first都相同时second大的pair就大。
了解完pair之后我们可以去研究set的insert了
val就是我们想插入set的数据,那么返回的键值对有什么价值呢?
这也是set和map可以实现去重的原因之一,除此以外,像find之类的函数也可以通过insert变相实现了
(4)erase、count、multiset
常用的是第二种,直接删除某个值,返回值是删除的值的个数。这个时候我们就有疑问了,直接用bool不好吗,删除了就是true,删不掉就是false,这是为了multiset准备的。
multiset是一个没有去重效果的set,可以用于除去重以外其他功能的实现
值得注意的是,multiset的大部分接口和set没什么两样,但是在set中有的接口设计会考虑去重,比如insert的返回值,而在multiset中这就没有必要了,所以存在一些不同之处
在find中multiset返回的就是第一个出现的val的迭代器
同样的,像count函数也存在erase类似处理的情况
count返回的是val在set中出现次数,就是为了统一set和multiset的接口用法
(5)lower_bound、upper_bound
这两个函数还是比较容易混的,我们先看看下面的代码
int main()
{set<int> s;s.insert(1);s.insert(2);s.insert(3);s.insert(4);s.insert(5);s.erase(s.lower_bound(2), s.upper_bound(4));for (const auto& e : s){cout << e << " ";}return 0;
}
输出结果是
lower_bound和upper_bound返回的是对应值的迭代器吗?如果真是这样,那4就不应该被删掉,且和find就没区别了。
事实上,对于lower_bound而言,它返回的是按迭代器遍历顺序大于等于val的值的迭代器,在上面的代码中2存在,于是就把2对应的迭代器返回了回去,如果2不存在就会向上找。
而upper_bound返回的是按迭代器遍历顺序大于val的值的迭代器,在上面的代码中4虽然存在,但它会找比4大的值,返回的是5的迭代器,因此erase按左闭右开的规则会删掉4。
两种迭代器都是向比自己大的值去找,但lower_bound要找等于自己的,upper_bound不找。在erase中却很好理解,s.erase(s.lower_bound(2), s.upper_bound(4));就是删掉2到4之间的所有值(闭区间)。在所有迭代器的组合使用中,都是左闭右开,lower_bound对应左,upper_bound对应右,这样你就明白为什么这样设计了。
如果找不到符合规则的迭代器,那就会返回end。
(6)find
前面我已经介绍了find,这里为什么还要介绍呢?前面的find是set容器里自带的,而这里我想讨论算法库的find和容器里的find的区别
在算法库中,find前两个参数是迭代器区间,第三个是要查找的值
而在set中,不需要前两个参数了。
似乎两者没什么区别,但在底层上区别就很大了。算法库的find只能根据迭代器不断++来找。在set和map中迭代器的顺序就是中序的顺序。但对于set自带的find而言就不是按照中序来找数据了,而是按照平衡二叉搜索树的特点左小右大来找了,在高度次内就能找到。算法库的时间复杂度是O(N),而自带的find时间复杂度是O(logN)
相关文章:

C++相关概念和易错语法(23)(set、仿函数的应用、pair、multiset)
1.set和map存在的意义 (1)set和map的底层都是二叉搜索树,可以达到快速排序(当我们按照迭代器的顺序来遍历set和map,其实是按照中序来遍历的,是排过序的)、去重、搜索的目的。 (2&a…...

netty入门-3 EventLoop和EventLoopGroup,简单的服务器实现
文章目录 EventLoop和EventLoopGroup服务器与客户端基本使用增加非NIO工人NioEventLoop 处理普通任务与定时任务 结语 EventLoop和EventLoopGroup 二者大概是什么这里不再赘述,前一篇已简述过。 不理解也没关系。 下面会简单使用,看了就能明白是什么 这…...

通信原理-思科实验五:家庭终端以太网接入Internet实验
实验五 家庭终端以太网接入Internet实验 一实验内容 二实验目的 三实验原理 四实验步骤 1.按照上图选择对应的设备,并连接起来 为路由器R0两个端口配置IP 为路由器R1端口配置IP 为路由器设备增加RIP,配置接入互联网的IP的动态路由项 5.为路由器R1配置静…...
【Vue】vue概述
1、简介 Vue.js(简称Vue)是一款用于构建用户界面的渐进式JavaScript框架。由前Google高级软件工程师尤雨溪(Evan You)于2014年创建,是一个独立且社区驱动的开源项目。Vue.js基于标准的HTML、CSS和JavaScriptÿ…...
Docker use experience
#docker command docker load -i <镜像文件.tar> docker run -it -d --name 容器名 -p 宿主机端口:容器端口 -v 宿主机文件存储位置:容器内文位置 镜像名:Tag /bin/bash docker commit -m"提交的描述信息" -a"作者" 容器ID 要…...

Android平台RTSP|RTMP直播播放器技术接入说明
技术背景 大牛直播SDK自2015年发布RTSP、RTMP直播播放模块,迭代从未停止,SmartPlayer功能强大、性能强劲、高稳定、超低延迟、超低资源占用。无需赘述,全自研内核,行业内一致认可的跨平台RTSP、RTMP直播播放器。本文以Android平台…...

数据结构——栈(顺序结构)
一、栈的定义 栈是一种数据结构,它是一种只能在一端进行插入和删除操作的特殊线性表。这一端被称为栈顶,另一端被称为栈底。栈按照后进先出(LIFO)的原则进行操作(类似与手枪装弹后射出子弹的顺序)。在计算…...
速盾:cdn能防御ddos吗?
CDN(内容分发网络)是一种广泛应用于互联网中的技术,它通过将内容分发到全球各地的服务器上,以提高用户在访问网站时的加载速度和稳定性。然而,CDN是否能够有效防御DDoS(分布式拒绝服务)攻击是一…...

分享 2 个 .NET EF 6 只更新某些字段的方法
前言 EF 更新数据时,通常情况下,是更新全部字段的,但实际业务中,更新全部字段的情况其实很少,一般都是修改其中某些字段,所以为了实现这个目标,很多程序员通常会这样作: 先从数据库…...

vs code解决报错 (c/c++的配置环境 远端机器为Linux ubuntu)
参考链接:https://blog.csdn.net/fightfightfight/article/details/82857397 https://blog.csdn.net/m0_38055352/article/details/105375367 可以按照步骤确定那一步不对,如果一个可以就不用往下看了 目录 一、检查一下文件扩展名 二、安装扩展包并…...

08 字符串和字节串
使用单引号、双引号、三单引号、三双引号作为定界符(delimiter)来表示字符串,并且不同的定界符之间可以相互嵌套。 很多内置函数和标准库对象也都支持对字符串的操作。 x hello world y Python is a great language z Tom said, "Le…...
vue使用mavonEditor(流程图、时序图、甘特图实现)
mavonEditor 安装mavonEditor $ npm install mavon-editor --save使用 // 全局注册import Vue from vueimport mavonEditor from mavon-editorimport mavon-editor/dist/css/index.css// useVue.use(mavonEditor)new Vue({el: #main,data() {return { value: }}})//局部使用…...

Java实现短信验证码服务
1.首先这里使用的是阿里云的短信服务。 package com.wzy.util;; import cn.hutool.captcha.generator.RandomGenerator; import com.aliyun.dysmsapi20170525.Client; import com.wzy.entity.Ali; import org.springframework.stereotype.Component;/*** Author: 顾安* Descri…...
python中的线程
线程 线程概念 线程 在一个进程的内部, 要同时干多件事, 就需要同时运行多个"子任务", 我们把进程内的这些"子任务"叫做线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中, 是进程的实际运作单位。一条线程指的是进程中一个单一顺序的控制流…...
hcip学习 多实例生成树,VRRP工作原理
一、STP 和 RSTP 解决了什么问题 1、STP:解决了在冗余的二层网络中所出现的环路问题 2、RSTP:在 STP 的基础上,解决了 STP 收敛速度慢的问题,引入了一些 STP 保护机制,使其网络更加稳定 二、MSTP 针对 RSTP 的改进 …...

Docker搭建群晖
Docker搭建群晖 本博客介绍在docker下搭建群晖 1.编辑docker-compose.yml文件 version: "3" services:dsm:container_name: dsmimage: vdsm/virtual-dsm:latestenvironment:DISK_SIZE: "16G"cap_add:- NET_ADMIN ports:- 8080:50…...
【java】BIO,NIO,多路IO复用,AIO
在Java中,处理I/O操作的模型主要有四种:阻塞I/O (BIO), 非阻塞I/O (NIO), 异步I/O (AIO), 以及IO多路复用。下面详细介绍这四种I/O模型的工作原理和应用场景。 1. 阻塞I/O (BIO) 工作原理 阻塞I/O是最传统的I/O模型。在这种模型中,当一个线…...
服务器怎样减少带宽消耗的问题?
择业在使用服务器的过程中会消耗大量的带宽资源,而减少服务器的带宽消耗则可以帮助企业降低经济成本,同时还能够提高用户的访问速度,那么服务器怎样能减少带宽的消耗呢?本文就来带领大家一起来探讨一下吧! 企业可以选择…...
linux 报错:bash: /etc/profile: 行 32: 语法错误:未预期的文件结束符
目录 注意错误不一定错在最后一行 i进入编辑 esc退出编辑 :wq 保存编辑退出 :q!不保存退出 if [ $# -eq 3 ] then if [ ! -e "$1" ]; then miss1 $1 elif [ ! -e "$2" -a ! -e "$3" ]; then miss2and3…...

MySQL练习(5)
作业要求: 实现过程: 一、触发器 (1)建立两个表:goods(商品表)、orders(订单表) (2)在商品表中导入商品记录 (3)建立触发…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...