面向对象程序设计——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.mzph.cn/bicheng/54606.shtml

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

相关文章

图片马赛克处理(Java)

1.需求 给图片的指定区域打码给整张图片打码马赛克方格取色支持中心点取色和随机取色马赛克支持灰度处理 2.源码 package com.visy.utils;import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOE…

(k8s)Kubernetes部署Promehteus

转载&#xff1a;Kubernetes&#xff08;k8s&#xff09;部署Promehteus 一、概述 在1.8版本以后heapster由metrics-server替代&#xff1b;从k8s的v1.11版本开始已经全面转向以Prometheus为核心的新监控体系架构&#xff1b;kube-prometheus 中包含了 prometheus 监控所用到的…

pg入门18—如何使用pg gis

1. 下载postgre gis镜像 2. 运行镜像 docker run -p 15432:5432 -d -e POSTGRES_PASSWORDAb123456! postgis/postgis:12-3.4-alpine 3. 使用gis # 进入容器&#xff0c;登录pgdocker exec -it bash# 登录数据库psql -U postgres# 创建数据库CREATE DATABASE mygeotest;# 使用…

算法:双指针题目练习

文章目录 算法:双指针移动零复写零快乐数盛最多水的容器有效三角形的个数查找总价格为目标值的两个商品三数之和四数之和 总结 算法:双指针 移动零 定义两个指针,slow和fast.用这两个指针把整个数组分成三块. [0,slow]为非零元素,[slow1,fast-1]为0元素,[fast,num.length]为未…

【Web】御网杯信息安全大赛2024 wp(全)

目录 input_data admin flask 如此多的FLAG 一夜醒来之全国CTF水平提升1000倍&#x1f60b; input_data 访问./.svn后随便翻一翻拿到flag admin dirsearch扫出来 访问./error看出来是java框架 测出来是/admin;/路由打Spring View Manipulation(Java)的SSTI https:/…

基于ECC簇内分组密钥管理算法的无线传感器网络matlab性能仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于ECC簇内分组密钥管理算法的无线传感器网络matlab性能仿真&#xff0c;对比网络通信开销&#xff0c;存活节点数量&#xff0c;网络能耗以及数据通信量四个指标…

【Linux篇】TCP/IP协议(笔记)

目录 一、TCP/IP协议族体系结构 1. 数据链路层 &#xff08;1&#xff09;介绍 &#xff08;2&#xff09;常用协议 ① ARP协议&#xff08;Address Resolve Protocol&#xff0c;地址解析协议&#xff09; ② RARP协议&#xff08;Reverse Address Resolve Protocol&…

华为为什么要做三折叠屏手机?

前些天我做了一条视频&#xff0c;关于讲华W的新的三折叠屏手机。我说我有点失望&#xff0c;结果引起了华W的同事的一些关注。于是&#xff0c;华W几位高管都跑过来&#xff0c;跟我解释为什么会出现这样的一个状态。 我才知道&#xff0c;这款手机他们其实是亏着钱在卖的。因…

C++速通LeetCode中等第1题-字母异位词分组

思路要点&#xff1a;对字符串排序&#xff0c;排序结果存放在map的key中&#xff0c;排序结果相同的字符串存放到map的value中 。 class Solution { public:string keys;vector<vector<string>> groupAnagrams(vector<string>& strs) {vector<vecto…

EECS498 Deep Learning for Computer Vision (一)软件使用指南

#最近开始学习深度学习的相关基础知识&#xff0c;记录一下相关笔记及学习成果# learning&#xff1a;building artificial systems that learn from data and experience deep learning(a set of machine learning): hierarchical learning algorithms with many "laye…

海洋大地测量基准与水下导航系列之二国外海底大地测量基准和海底观测网络发展现状(上)

海底大地控制网建设构想最先由美国斯克里普斯海洋研究所(Scripps Institution of Oceanography,SIO)提出&#xff0c;目前仅有少数发达国家具备相应技术条件。美国、日本、俄罗斯和欧盟等发达国家通过布测先进的海底大地控制网&#xff0c;不断完善海洋大地测量基准基础设施&am…

6、等级保护政策内容

数据来源&#xff1a;6.等级保护政策内容_哔哩哔哩_bilibili 信息安全产品管理与响应 等级管理 对信息系统中使用的信息安全产品实行按等级管理&#xff0c;信息安全事件应分等级响应与处置。 预测评服务由测评公司和咨询公司提供预测评服务&#xff0c;根据技术要求和测评要…

深度学习01-概述

深度学习是机器学习的一个子集。机器学习是实现人工智能的一种途径&#xff0c;而深度学习则是通过多层神经网络模拟人类大脑的方式进行学习和知识提取。 深度学习的关键特点&#xff1a; 1. 自动提取特征&#xff1a;与传统的机器学习方法不同&#xff0c;深度学习不需要手动…

前端工程化4:从0到1构建完整的前端监控平台

前言 一套完整的前端监控系统的主要部分&#xff1a; 数据上报方式数据上送时机性能数据采集错误数据采集用户行为采集定制化指标监控sdk 监控的目的&#xff1a; 一、数据上报方式 本文的方案是&#xff0c;优先navigator.sendBeacon&#xff0c;降级使用1x1像素gif图片…

Python3网络爬虫开发实战(17)爬虫的管理和部署(第一版)

文章目录 一、 Scrapyd 分布式部署1.1 了解 Scrapyd1.2 准备工作1.3 访问 Scrapyd1.4 Scrapyd 的功能1.5 ScrapydAPI 的使用 二、Scrapyd-Client 的使用2.1 准备工作2.2 Scrapyd-Client 的功能2.3 Scrapyd-Client 部署 三、Scrapyd 对接 Docker3.1 准备工作3.2 对接 Docker 四、…

Linux网络工具:用于查询DNS(域名系统)域名解析信息的命令nslookup详解

目录 一、概述 二、基本功能 1、查询域名对应的IP地址 2、查询IP地址对应的主机名 3、查询特定类型的DNS记录 三、用法 1、命令格式 2、常用选项 五、nslookup的安装 1. 打开终端 2. 更新的系统包列表 3. 安装 bind-utils 软件包 &#xff08;1&#xff09;对于Ce…

Vue点击按钮生成pdf文件/Vue点击按钮生成png图片

本次案例是vue的点击生成pdf文件和png格式的图片 一、生成pdf文件案例 看代码之前&#xff0c;我们肯定得需要看看&#xff0c;效果图是什么的啦&#xff0c;这样子才能先看看自己想要实现的效果是不是这样子的&#xff01;上效果图嘿嘿嘿~ A、实现的效果图 这是页面&#…

java intellij idea开发步骤,使用指南,工程创建与背景色字体配置,快捷键

intellij idea2021 配置背景色&#xff0c;字体大小&#xff0c;主题 快捷键

JACM23 - A New Algorithm for Euclidean Shortest Paths in the Plane

前言 如果你对这篇文章感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 本文关注的问题为计算几何学中的经典问题&#xff0c;即「在平面上给定一组两两不相交的多边形障碍物&#xff0c;寻找两点…

linux设置常见开机自启动命令

本文介绍了三种开机自启的方式&#xff0c;重点介绍使用systemctl的方式自启动的 方式一、修改 /etc/rc.d/rc.local 文件 /etc/rc.d/rc.local 文件会在 Linux 系统各项服务都启动完毕之后再被运行。所以你想要自己的脚本在开机后被运行的话&#xff0c;可以将自己脚本路径加到…