红黑树下探玄机:C++ setmultiset 的幕后之旅

目录

一、关联式容器

二、键值对

三、set

四、set的构造

五、set的iterator

六、set的Operations

七、multiset


一、关联式容器

序列式容器 : 

  1.  在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、forward_list(C++11)等
  2. 底层为线性序列的数据结构,里面存储的是元素本身

关式容器联 : 

  1. 也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高

二、键值对

键值对 : 用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息

使用场景 :
现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义

pair的结构

template<class T1,class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;pair()
:first(T1())
,second(T2())
{}pair(const T1& a,const T2& b)
:first(a)
,second(b)
{}
};

三、set

  • T: set中存放元素的类型,实际在底层存储<value, value>的键值对
  • Compare:set中元素默认按照小于来比较
  • Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理

在使用set中,set相当于只存一个值,在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的,且set是按照一定次序存储元素的容器

在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序,set中的元素按一定次序排序,且元素唯一,元素不能在set中被修改 (元素总是const) ,只能被插入或删除 ,set在底层是用二叉搜索树(红黑树)实现的

注意记忆的点:

  • set中只放value,但在底层实际存放的是由<value, value>构成的键值对
  • set中插入元素时,只需要插入value即可,不需要构造键值对pair
  •  set中的元素不可以重复(因此可以使用set进行去重)
  • 使用set的迭代器遍历set中的元素,可以得到有序序列
  • set中的元素默认按照小于来比较
  • set中查找某个元素,时间复杂度为:log2(N)

四、set的构造

  1. empty : set的无参的构造 
  2. range :使用一段迭代器区间构造
  3. copy :拷贝构造 

operator=

#include <iostream>
#include <set>using namespace std;int main()
{set<int> s1;int arr[] = { 9,8,7,6,5,4,3 };set<int> s2(arr, arr + sizeof(arr) / sizeof(arr[0]));set<int> s3(s2);s1 = s2;return 0;
}


五、set的iterator

  • 返回第一个元素的iterator

  • 返回最后一个元素的iterator
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3 };set<int> s2(arr, arr + sizeof(arr) / sizeof(arr[0]));set<int>::iterator it = s2.begin();set<int>::iterator it1 = s2.end();while (it != it1){cout << *it << " ";it++;}return 0;
}


  • 判断set是否为空

  • 返回set的元素个数

  • single element : 插入一个key(val)返回一个键值对pair,在pair中第一个数据first是插入位置的迭代器,第二个位置是->是否插入成功,set中的key值不能重复且只能有一个,如果key值已经有了,那么返回的是原key位置的迭代器以及false,如果key值没有,那么返回的是新插入key位置的迭代器以及true,由于return不能返回两个值,所以如果想返回多个值,必须放在一个结构中进行返回,这里是放在了键值对pair中进行返回
  • with hint : 在一个迭代器位置插入一个key(val),传入的这个iterator 位置对于编译器来说只是一个建议位置,实际插入数据还是根据其原有的二叉搜索树的逻辑 (有序) 进行插入
  • range : 是插入一段迭代器区间
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3 };set<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));set<int>::iterator it=s2.insert(s2.begin(), 2);cout << *it << endl;pair<set<int>::iterator, bool> pa = s2.insert(9);cout << *(pa.first) << " "<<pa.second << endl;return 0;
}


  • void erase : 删除某个 iterator 
  • size_ t erase : 删除某个key值,返回值是删除的这个key值的个数 , 返回的个数这是为了后面的 multiset 做准备,因为multiset可以允许有多个相同的key值,而set和mulitset的关联性很大,所以为了接口的统一性将这里的删除值为key的erase的操作的返回值设置为了返回删除key值的个数,在set中当有这个key值的 时候删除对应的节点成功返回1,当没有这个key值的时候删除对应节点失败返回 0
  • void erase : 删除一段迭代器区间
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3 };set<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));s2.erase(s2.begin());size_t ret = s2.erase(8);cout << ret << endl;s2.erase(s2.begin(), s2.end());return 0;
}


  • swap是交换两个set对象的数据
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3 };set<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));set<int> s3;s3.swap(s2);return 0;
}


  • 清空set的所有元素
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3 };set<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));s2.clear();return 0;
}


六、set的Operations

  • find是查找一个元素的iterator,如果没有查找到那么返回end()iterator
  • set的底层是红黑树,在二叉搜索数的基础上进行了平衡,所以成员函数find的查找效率高为O(logN),,库里也有find,由于库里的是给出区间遍历查找,时间复杂度为O(N) ,所以单独提供了find
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3 };set<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));cout << *(s2.find(9)) << endl;return 0;
}


  • count是返回key值对应的个数 ,同样是为了和multiset保持接口的一致性,multiset允许多个key值存在,所以当myltiset调用count的时候可能key值对应的个数会有多个,为了set和multiset接口的统一性,我们给set也提供一个count接口,count接口在set中可以用于判空
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3 };set<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));cout << s2.count(7) << endl;return 0;
}


  • lower_bound是下界(>=)的意思,即寻找比给定key值等于大于的值的位置的迭代器,有等于优先是等于,其次是大于,如果找不到那么返回end()

  • upper_bound(>)是上界的意思,即寻找比给定key值大的值的位置的迭代器,如果找不到那么返回end()

lower_bound和upper_bound通常是搭配使用,用于寻找指定区间的迭代器(前闭区间 ,后开区间),通常要使用erase或insert插入一段区间,对区间进行操作,那么就会用到这两个函数

erase:

#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3 };set<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));set<int>::iterator it1 = s2.lower_bound(5);// >=5set<int>::iterator it2 = s2.upper_bound(6);// >6// erase: [5 ,6 ) ,删除掉 5 和6  s2.erase(it1, it2);for (auto e : s2){cout << e << endl;}return 0;
}


  • equal_range的意思是相等的范围,即去寻找和key值相等序列的开头和结尾位置的迭代器,同理 ,这里同样是为了和multiset保持接口的一致性,即multiset中可以有多个相同的key值,即使用equal_range去找key值会找到的是一段序列
  • 返回的pair中第一个iterator 是 和key值相等序列的开头位置的iterator , 第二个是结尾位置的迭代器 
  • 如果给equal_range的key值,在set中没有,那么会返回比key值大的位置的迭代器作为开头位置的迭代器和结尾位置的迭代器进行返回,举例set数据序列为1,5,7,那么传入查找3作为key值进行查找,3没有,那么就会找比key值3大的值的迭代器即5位置的迭代器作为开头和结尾位置的迭代器,那么就会返回[5,5),那么由于成员函数对序列区间进行操作是前闭区间后开区间,那么[5,5)这个序列就相当于不存在的区间,如果比key值(key值不存在set的数据序列中)大的位置的值都没有那么会返回end()作为开头和结尾的位置的迭代器即[end(),end()),即如果给equal_range的key值不存在,那么equal_range会返回一个不存在的区间

七、multiset

  • multiset与set 的唯一不同是multiset中可以有多个相等的key值
  • multiset的其它性质和set类似
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3,8,7,6,5,4,3,8 };multiset<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));for (auto e : s2){cout << e <<" ";}cout << endl;return 0;
}

multiset的count

#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3,8,7,6,5,4,3,8 };multiset<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));cout << s2.count(9);cout << endl;cout << s2.count(7) << endl;return 0;
}

multiset的erase

  • 与set不同的是,multiset删除key值,如果key值有多个,那么会将多个相同的key值同时删除
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3,8,7,6,5,4,3,8 };multiset<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));s2.erase(4);for (auto e : s2){cout << e << " ";}return 0;
}

multiset的find

  • 与set不同的是,multiset的find的key值可能会有对应的多个相等的key值,那么find会返回迭代器遍历(中序遍历)中的第一个key值位置的迭代器
#include <iostream>
#include <set>
using namespace std;
int main()
{int arr[] = { 9,8,7,6,5,4,3,8,7,6,5,4,3,8 };multiset<int> s2;s2.insert(arr, arr + sizeof(arr) / sizeof(arr[0]));set<int>:: iterator it = s2.find(7);//找到第一个7cout << *(it) << endl;it++;cout << *(it) << endl;//是按有序的排列,第一个7后面也是7  ,说明是第一个7return 0;
}

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

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

相关文章

Spring : 事务管理

1. 基本概念 事务&#xff08;Transaction&#xff09;是一组不可分割的操作单元&#xff0c;这些操作要么全部成功执行&#xff0c;要么全部失败回滚&#xff0c;不存在部分成功的情况。 事务具有ACID特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事…

C# 一个投资跟踪程序的设计与实现:面向对象与设计模式的深度解析

在现代金融应用开发中&#xff0c;如何高效、灵活地构建投资跟踪系统&#xff0c;是每一个金融软件工程师必须面对的挑战。本文将围绕一个投资跟踪程序的设计与实现过程&#xff0c;深入剖析其背后的设计理念、架构模式以及具体实现细节。我们将通过面向对象编程、设计模式&…

存储的未来之战:RustFS如何用ZK框架重构分布式协调?

本篇文章目录 一、导火索&#xff1a;当数据洪峰撞上分布式协调的天花板 二、技术密码&#xff1a;ZK框架的三大重构 2.1 一致性哈希环的量子级进化 2.2 动态负载均衡的"神经反射" 2.3 跨云数据同步的"时空折叠" 三、未来战争&#xff1a;2026年存储…

模拟实现STL中的list容器

list前言一、list的节点结构设计二、迭代器设计三、list类的实现3.1 类的成员变量和类型定义3.2 构造函数与析构函数3.3 元素访问与迭代器接口3.4 插入与删除操作3.5 其他常用操作四、总结每文推荐前言 在C STL中&#xff0c;list是一个非常常用的容器&#xff0c;它基于双向循…

Debug-039-el-date-picker组件手动输入时间日期的问题处理

图1-外输入框图2-内输入框图3问题描述&#xff1a;这两天在迭代功能的时候&#xff0c;基本上碰到的问题都是出自这个“时间日期选择框”&#xff0c;昨天的bug38也是解决这个组件。如上图1和2所示&#xff0c;可以把图1中的输入框叫外输入框&#xff0c;图2中的输入框叫内输入…

docker-runc not installed on system

问题 Docker build时Dockerfile有RUN命令执行报错shim error: docker-runc not installed on system&#xff0c;如下&#xff1a;解决方法 修改/etc/docker/daemon.json&#xff0c;添加正面内容 {"runtimes": {"docker-runc": {"path": "…

【秋招笔试】2025.08.27华为秋招研发岗真题

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围在线刷题 bishipass.com 题目一:智能温控系统监测 1️⃣:使用滑动窗口技术维护有效温度区间 2️⃣:利用单调队列高效维护窗口内的最大值和最小值 3️⃣:动态调整窗口边界,确保满足温…

Kafka 消费模型

文章目录1. 一个消费者组中只有 1 个消费者2. 一个消费者组中有 2 个消费者3. 消费者数量 > 分区数量4. 多个消费者读取同一个分区5. 消费者放入消费者组5.1 何时放入同一个消费者组5.2 何时放入不同的消费者组1. 一个消费者组中只有 1 个消费者 假设我们有一个 TopicT1&am…

【路由器】TP Link 路由器为何无法进入管理后台

TL-WR710N是TP Link在很多年前发布的一个迷你型的便携路由器&#xff0c;一插上还能用&#xff0c;直接reset打算重设密码&#xff0c;结果根据它给的192.168.1.253根本打不开。# 解决方法ping一下192.168.1.253&#xff0c;无法连接。这个问题本质上是 你电脑/手机的 IP 和路由…

LightGBM(Light Gradient Boosting Machine,轻量级梯度提升机)梳理总结

LGB微软团队在 2017 年提出的梯度提升树模型&#xff0c;核心定位是 “更高效的 XGBoost”—— 它在保持精度接近 XGBoost 的同时&#xff0c;通过“数据采样优化”“特征压缩”“树生长策略改进”三大创新&#xff0c;将训练速度提升 10-100 倍&#xff0c;内存消耗降低数倍&a…

毕业项目推荐:29-基于yolov8/yolov5/yolo11的光伏板检测识别系统(Python+卷积神经网络)

文章目录 项目介绍大全&#xff08;可点击查看&#xff0c;不定时更新中&#xff09;概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式…

【实时Linux实战系列】实时数据可视化技术实现

在当今数据驱动的世界中&#xff0c;实时数据可视化已成为理解和利用实时信息的关键工具。无论是在金融交易监控、工业生产监控、智能交通管理还是物联网设备监控中&#xff0c;能够将复杂的数据以直观的图表形式展示出来&#xff0c;对于快速决策和问题解决至关重要。实时数据…

【LeetCode每日一题】21. 合并两个有序链表 2. 两数相加

每日一题21. 合并两个有序链表题目总体思路算法步骤时间复杂度与空间复杂度代码2. 两数相加题目总体思路算法步骤时间复杂度与空间复杂度代码知识感悟2025.8.3021. 合并两个有序链表 题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所…

DVWA靶场通关笔记-文件包含(Impossible级别)

目录 一、源码分析 二、文件包含防范分析 1、明确指定允许包含的文件 2、拒绝所有未在白名单中的输入 3、总结 &#xff08;1&#xff09;白名单 (Allow List) &#xff08;2&#xff09;硬编码/映射 (Hardcoding/Mapping) &#xff08;3&#xff09;输入过滤 (Input F…

构建坚不可摧的数据堡垒:深入解析 Oracle 高可用与容灾技术体系

在当今数字化时代&#xff0c;数据是企业的核心资产&#xff0c;而承载这些数据的数据库系统的连续性与稳定性直接关系到企业的生死存亡。一次计划外的停机或灾难性的数据丢失&#xff0c;带来的不仅是经济上的巨大损失&#xff0c;更是对品牌信誉和客户信任的致命打击。因此&a…

【3D算法技术入门】如何基于建筑图片重建三维数字资产?

要基于建筑图片重建三维数字资产是一个复杂的计算机视觉任务&#xff0c;涉及图像采集、特征提取、相机姿态估计、稠密重建和三维模型优化等多个步骤。下面我将提供一个基于Python的解决方案框架&#xff0c;使用开源库实现从图片到三维模型的基本流程。 首先需要安装必要的库&…

⭐CVPR2025 自动驾驶半监督 LiDAR 分割新范式:HiLoTs 框架深度解析

&#x1f4c4;论文题目&#xff1a;HiLoTs: High-Low Temporal Sensitive Representation Learning for Semi-Supervised LiDAR Segmentation in Autonomous Driving ✍️作者及机构&#xff1a; R.D. Lin、Pengcheng Weng、Yinqiao Wang、Fei Wang&#xff08;西安交通大学软件…

【 MYSQL | 基础篇 函数与约束 】

摘要&#xff1a;本文介绍数据库中的函数与约束&#xff0c;函数含字符串、数值、日期、流程四类&#xff0c;可实现字符串处理、数值计算等需求。约束分六类&#xff0c;重点讲外键约束的语法、删除更新行为&#xff0c;保证数据正确完整。思维导图1. 函数函数是指一段可以直接…

Oracle 数据库性能调优:从瓶颈诊断到精准优化之道

引言&#xff1a;性能优化的本质在当今数据驱动的时代&#xff0c;数据库性能直接关系到企业的运营效率和用户体验。Oracle 作为全球领先的关系型数据库管理系统&#xff0c;承载着众多企业的核心业务。然而&#xff0c;随着数据量的增长和业务复杂度的提升&#xff0c;数据库性…

杨校老师竞赛课堂之C++语言GESP一级笔记

考试大纲 GESP一级考试大纲 计算机基础与编程环境 计算机历史 变量的定义与使用 基本数据类型&#xff08;整型、浮点型、字符型、布尔型&#xff09; 输入与输出&#xff08;cin与cout、scanf与printf&#xff09; 基本运算&#xff08;算术运算、关系运算、逻辑运算&am…