面向对象程序设计——set容器の简析

1.set的介绍

• 序列式容器和关联式容器

• 我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间⼀般没有紧密的关联关系,⽐如交换⼀下,他依旧是序列式容器。

• 顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的。

• 关联式容器也是⽤来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是⾮线性结构, 两个位置有紧密的关联关系,交换⼀下,他的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的。关联式容器有map/set系列和unordered_map/unordered_set系列。set底层是红⿊树,红⿊树是⼀颗平衡⼆叉搜索树。set是key搜索场景的结构

• set的声明如下:

T就是set底层关键字的类型 • set默认要求T⽀持⼩于⽐较,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模版参数

• set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第三个参数

• ⼀般情况下,我们都不需要传后两个模版参数

• set底层是⽤红⿊树实现,增删查效率是,迭代器遍历是⾛的搜索树的中序,所以是有序的 

2.set的增删查 

2.1插入(insert)

插入接口的介绍 

// 单个数据插⼊,如果已经存在则插⼊失败 
pair<iterator,bool> insert (const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊ 
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊ 
template <class InputIterator>
void insert (InputIterator first, InputIterator last);

插入接口的使用 

set容器在插入后默认是升序存储的,并且无法插入重复的元素,但是可以使用仿函数来传参实现降序,也可以插入一段元素,通常使用ASCII码来进行比较大小

//插入
int main()
{//去重+默认升序排列set<int> s1;s1.insert(2);s1.insert(4);s1.insert(3);s1.insert(2);s1.insert(5);s1.insert(9);//迭代器遍历//set<int, greater<int>>::iterator it = s1.begin();auto it_s1 = s1.begin();while (it_s1 != s1.end()){//*it = 1;---->error//不可以修改cout << *it_s1 << " ";++it_s1;}cout << endl;//去重+使用仿函数降序排列set<int,greater<int>> s2;s2.insert(2);s2.insert(4);s2.insert(3);s2.insert(2);s2.insert(5);s2.insert(9);//迭代器遍历//set<int, greater<int>>::iterator it = s2.begin();auto it_s2 = s2.begin();while (it_s2 != s2.end()){cout << *it_s2 << " ";++it_s2;}cout << endl;//插⼊⼀段initializer_list列表值,已经存在的值插⼊失败set<int> s3;s3.insert({ 2,3,4,5,5,7,9,11 });for (auto e : s3){cout << e << " ";}cout << endl;//插入string类,通过ASCII码的大小来排序set<string> s4;s4.insert({ "zhangsan", "lisi", "wangwu" });for (auto e : s4){cout << e << " ";}cout << endl;return 0;
}

2.2查找(find)

在算法库中的find使用的是遍历查找,时间复杂度是O(N)

set自身的find是符合平衡二叉树的查找,时间复杂度O(logN)

// 算法库的查找 O(N) auto pos1 = find(s.begin(), s.end(), x); // set⾃⾝实现的查找 O(logN) auto pos2 = s.find(x); 

查找接口的介绍 

// 查找val,返回val所在的迭代器,没有找到返回end() 
iterator find (const value_type& val);
// 查找val,返回Val的个数 
size_type count (const value_type& val) const;

查找接口的使用 

1. find接口直接删除

int main()
{//去重+默认升序排列set<int> s;s.insert(2);s.insert(4);s.insert(3);s.insert(2);s.insert(5);s.insert(9);//迭代器遍历//set<int, greater<int>>::iterator it = s.begin();auto it = s.begin();while (it != s.end()){//*it = 1;---->error//不可以修改cout << *it << " ";++it;}cout << endl;int x = 0;cout << "请输入你要查找的数字:";cin >> x;//如果查找不到就会返回迭代器的尾部/*auto pos = s.find(x);if (pos != s.end()){cout << x << "存在" << endl;}else{cout << x << "不存在" << endl;}*/return 0;
}

count函数间接查找 

//使用count来间接查找//count可以统计元素出现的次数,如果出现0次就不存在,反之则存在if (s.count(x)){cout << x << "存在" << endl;}else{cout << x << "不存在" << endl;}

2.3删除(erase)

删除接口的介绍 

// 删除⼀个迭代器位置的值 
iterator erase (const_iterator position);
// 删除val,val不存在返回0,存在返回1 
size_type erase (const value_type& val);
// 删除⼀段迭代器区间的值 
iterator erase (const_iterator first, const_iterator last);

有关查找区间的迭代器

首先了解一个概念就是迭代器区间通常都是左闭右开的一个范围区间,也就说[a,b)的一个类型,这里的lower_bound与upper_bound可以实现查找一个左闭右开的区间以供操作 

// 返回⼤于等val位置的迭代器 
iterator lower_bound (const value_type& val) const;
// 返回⼤于val位置的迭代器 
iterator upper_bound (const value_type& val) const;

删除接口的使用 

直接删除并判断是否删除成功 

//删除
int main()
{set<int> s;s.insert({ 2,4,5,2,6,8,10,15 });for (auto e : s){cout << e << " ";}cout << endl;//删除最小的元素就删除排序后的首元素s.erase(s.begin());for (auto e : s){cout << e << " ";}cout << endl;//指定删除元素并判断是否删除成功//可以使用erase的返回值统计待删除元素出现的次数来判断是否删除成功int x = 0;cout << "输入你要删除的元素:";cin >> x;int num = s.erase(x);if (num){cout << "删除成功" << endl;for (auto e : s){cout << e << " ";}cout << endl;}else{cout << "删除失败" << endl;for (auto e : s){cout << e << " ";}cout << endl;}return 0;
}

迭代器删除  

//删除
int main()
{set<int> s;s.insert({ 2,4,5,2,6,8,10,15 });for (auto e : s){cout << e << " ";}cout << endl;//指定删除元素并判断是否删除成功//可以使用erase的返回值统计待删除元素出现的次数来判断是否删除成功int x = 0;cout << "输入你要删除的元素:";cin >> x;//使用迭代器删除//如果未查找到则直接返回迭代器尾部auto pos = s.find(x);if (pos != s.end()){s.erase(x);cout << "删除成功" << endl;for (auto e : s){cout << e << " ";}cout << endl;}else{cout << "删除失败" << endl;for (auto e : s){cout << e << " ";}cout << endl;}return 0;
}

迭代器区间删除 

//迭代器区间删除
int main()
{set<int> s;for (int i = 0; i < 10; i++){s.insert(i * 10);}for (auto e : s){cout << e << " ";}cout << endl;//删除30到60区间的数据//取出 >=30 的迭代器指针,包括30auto low = s.lower_bound(30);//取出 >60 的迭代器指针,不包括60auto up = s.upper_bound(60);s.erase(low, up);for (auto e : s){cout << e << " ";}cout << endl;return 0;
}

3.multiset和set的差异 

multiset和set的使⽤基本完全类似,主要区别点在于multiset⽀持值冗余,那么 insert/find/count/erase都围绕着⽀持值冗余有所差异

小tips:中序第一个指的就是从根节点开始以左子树->根节点->右子树的顺序,当在左子树找到符合的值后继续从该值的左子树寻找,直到找不到为止,这时的节点就是中序的第一个

#include<iostream>
#include<set>
using namespace std;
int main()
{// 相⽐set不同的是,multiset是排序,但是不去重 multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };auto it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;// 相⽐set不同的是,x可能会存在多个,find查找中序的第⼀个 int x;cin >> x;auto pos = s.find(x);while (pos != s.end() && *pos == x){cout << *pos << " ";++pos;}cout << endl;// 相⽐set不同的是,count会返回x的实际个数 cout << s.count(x) << endl;// 相⽐set不同的是,erase给值时会删除所有的x s.erase(x);for (auto e : s){cout << e << " ";}cout << endl;return 0;
}

4.代码练习题 

4.1两个数组的交集

题目来源:349.两个数组的交集 ,这里使用set容器充当去重与排序的作用

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {vector<int> v;set<int> s1;set<int> s2;s1.insert(nums1.begin(),nums1.end());s2.insert(nums2.begin(),nums2.end());auto it1 = s1.begin();auto it2 = s2.begin();while(it1 != s1.end() && it2 != s2.end()){if(*it1 < *it2){it1++;}else if(*it1 > *it2){it2++;}else{v.push_back(*it1);it1++;it2++;}}return v;}
};

4.2环形链表II

题目来源:142.环形链表|| ,这里使用set存储的是链表每个节点,当插入到重复的节点时,该节点就是入环的第一个节点,此时直接返回即可

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *detectCycle(ListNode *head){set<ListNode*> L;ListNode* cur = head;while(cur){if(L.count(cur)){return cur;}else{L.insert(cur);}cur = cur->next;}return nullptr;}
};

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

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

相关文章

Qt --- 常用控件的介绍 --- 其他控件

一、QPushButton QWidget中设计到的各种属性/函数/使用方法&#xff0c;针对接下来要介绍的Qt的各种控件都是有效的。 使用QPushButton表示一个按钮&#xff0c;这也是当前我们最熟悉的一个控件了。这个类继承了QAbstractButton&#xff0c;这个类是一个抽象类&#xff0c;是…

Unity 设计模式 之 创建型模式 -【单例模式】【原型模式】 【建造者模式】

Unity 设计模式 之 创建型模式 -【单例模式】【原型模式】 【建造者模式】 目录 Unity 设计模式 之 创建型模式 -【单例模式】【原型模式】 【建造者模式】 一、简单介绍 二、单例模式 (Singleton Pattern) 1、什么时候使用单例模式 2、单例模式的好处 3、使用单例模式的…

【后端开发】JavaEE初阶—Theard类及常见方法—线程的操作(超详解)

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解多线程的知识哟~~~&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;【后端开发】JavaEE初阶—线程的理解和编程实现-CSDN博客 &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondl…

WIFI路由器的套杆天线简谈

❝本次推文简单介绍下WIFI路由器的套杆天线。 路由器天线 路由器在这个万物互联的时代&#xff0c;想必大家对其都不陌生。随着科技的发展&#xff0c;常用的路由器上的天线也越来越多&#xff0c;那么问题来了&#xff1a;天线越多&#xff0c;信号越好吗&#xff1f;路由器…

ChromaDB教程_2024最新版(上)

前言 在上一篇&#xff08;快捷入口&#xff09;文章中&#xff0c;博主提到了一个向量存储&#xff0c;其中用到了Chroma数据库。代码示例如下&#xff1a; vectordb Chroma.from_documents(documentsdocs,embeddingembedding,persist_directoryvector_dir )这是基于langc…

服务发现和代理实例的自动更新

☞ 返回总目录 1.服务发现的两种方式 StartFindService 方法 这是一个在后台启动的连续 “FindService” 活动&#xff0c;当服务实例的可用性发生变化时&#xff0c;会通过回调通知调用者。 它返回一个FindServiceHandle&#xff0c;可通过调用StopFindService来停止正在进行…

自动化立体仓库与堆垛机单元的技术参数

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载。 这份文件是一份自动化立体仓库与堆垛机单…

初识APC机制实现APC注入

参考&#xff1a;APC异步过程调用-CSDN博客 又是跟着红队蓝军师傅学免杀的一天&#xff0c;这节课介绍了APC机制和APC注入的实现。 APC介绍&#xff1a; APC&#xff0c;全称为Asynchronous Procedure Call&#xff0c;即异步过程调用&#xff0c;是指函数在特定线程中被异…

【HTTPS】对称加密和非对称加密

HTTPS 是什么 HTTPS 是在 HTTP 的基础上&#xff0c;引入了一个加密层&#xff08;SSL&#xff09;。HTTP 是明文传输的&#xff08;不安全&#xff09; 当下所见到的大部分网站都是 HTTPS 的&#xff0c;这都是拜“运营商劫持”所赐 运营商劫持 下载⼀个“天天动听“&…

Java ETL - Apache Beam 简介

基本介绍 Apache Beam是一个用于大数据处理的开源统一编程模型。它允许用户编写一次代码&#xff0c;然后在多个批处理和流处理引擎上运行&#xff0c;如Apache Flink、Apache Spark和Google Cloud Dataflow等。Apache Beam提供了一种简单且高效的方式来实现数据处理管道&…

【Node.js】初识微服务

概述 Node.js 的微服务架构是一种通过将应用程序分解为独立的、松耦合的小服务的方式进行系统设计。 每个微服务负责处理一个特定的业务功能&#xff0c;并且这些服务可以独立开发、部署、扩展和管理&#xff0c;并且可以通讯。 它的核心思想就是解耦。 微服务和微前端是类…

智慧校园建设解决方案建设系统简介

一、建设背景 1.1 政策背景 1.2 班牌的演变 1.3 建设愿景 二、 智慧班牌简介 三、智慧班牌系统 3.1 系统概述 3.2 软件平台功能交互简介 3.2.1 智慧班牌与管理平台间的功能关联 3.2.2 手机客户端&#xff08;管理员、教师、家长端&#xff09; 3.2.3 手机客户端&#x…

CleanClip --- 为Mac用户打造的智能剪贴板管理利器

CleanClip是一款专为Mac用户设计的强大剪贴板管理工具&#xff0c;旨在提升用户的工作效率和数据管理体验。它通过智能化的剪贴板内容管理&#xff0c;实现了Mac系统与用户操作之间的无缝衔接。CleanClip支持多种连接方式&#xff0c;包括系统级的快捷操作和自定义快捷键&#…

PHP API 框架:构建高效API的利器

在当今快速发展的互联网时代&#xff0c;API&#xff08;应用程序编程接口&#xff09;已成为连接不同应用程序和服务的关键。PHP&#xff0c;作为一种流行的服务器端脚本语言&#xff0c;提供了多种强大的框架来简化API的开发。本文将介绍PHP API框架的重要性&#xff0c;以及…

【宠物小精灵之收服(待更新)】

题目 代码 #include <bits/stdc.h> using namespace std; int f[1010][510]; int main() {int n, m, k;cin >> n >> m >> k;int c 0;for(int i 1; i < k; i){int cost, hp;cin >> cost >> hp;for(int j n; j > cost; j--){for(i…

yarn : 无法加载文件 C:\Users\Rog\AppData\Roaming\npm\yarn.ps1,因为在此系统上禁止运行脚本

yarn : 无法加载文件 C:\Users\Rog\AppData\Roaming\npm\yarn.ps1&#xff0c;因为在此系统上禁止运行脚本 设置命令行窗口默认以管理员身份运行&#xff0c;在此基础上输入以下代码&#xff0c;应该就好使了&#xff0c;切记&#xff0c;以下代码才是关键&#xff0c;我基本上…

肾癌的多模态预测模型-临床-组织学-基因组

目录 摘要 技术路线 ① lncRNA的预测模型 ②病理 WSI 的分类器 ③临床病理分类器 模型结果 与别的模型比较 同行评审学习 1&#xff09;使用lncRNA的原因 2&#xff09;模型临床使用意义 3&#xff09;关于截止值的使用 摘要 A multi-classifier system integrated…

树莓派3B驱动ST7735(内核)(代码篇)(TODO)

书接上回&#xff1a;树莓派3B驱动ST7735&#xff08;内核&#xff09;&#xff08;配置篇&#xff09;_st7735s驱动固件下载-CSDN博客&#xff0c;这次主要是精读一下树莓派内核中的ST7735驱动源码 &#xff08;TODO&#xff09;

Elasticsearch不停机切换(上云)方案

如何给飞行中的飞机换引擎? 背景 业务背景 略 技术背景 线下集群40个索引左右&#xff0c;总数据量不大,不到100G因为ES承担的业务鉴权业务&#xff0c;所以不能接受停机割接 还有就是ES中数据来自各个业务方&#xff0c;推送的时机不定&#xff0c;也没有完备的重推机制&…

ChatGPT 在国内使用的方法

AI如今很强大&#xff0c;聊聊天、写论文、搞翻译、写代码、写文案、审合同等等&#xff0c;ChatGPT 真是无所不能~ 作为一款出色的大语言模型&#xff0c;ChatGPT 实现了人类般的对话交流&#xff0c;最主要是能根据上下文进行互动。 接下来&#xff0c;我将介绍 ChatGPT 在国…