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

news2024/9/22 22:55:33

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 的迭代器指针,包括30
	auto low = s.lower_bound(30);

	//取出 >60 的迭代器指针,不包括60
	auto 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.coloradmin.cn/o/2156054.html

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

相关文章

Python GUI 编程:tkinter 初学者入门指南——窗口

目录&#xff1a; 创建窗口更改窗口标题更改窗口大小和位置窗口在屏幕上居中窗口设置的其他属性 Tkinter 是在 Python 中开发 GUI&#xff08;图形用户界面&#xff09;最常用的库。在本指南中&#xff0c;我们将引导您了解 Tkinter 的基本知识&#xff0c;学习如何使用 Tkinte…

汽车电子零部件(16):ZCU区域控制器

ZCU(Zone Control Unit,区域控制器),功能主要包括哦数据交互、信号控制及电力分配等,是智能网联汽车中不可或缺的关键组件,ECU负责车身、车门、车窗、天窗、车灯(外大灯、内氛围灯)、座椅(可能包括座椅音响)、雷达甚至后排娱乐系统等控制执行单元的集中化。 CCU(centr…

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

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

Vue3新组件transition(动画过渡)

transition组件&#xff1a;控制V-if与V-show的显示与隐藏动画 1.基本使用 <template><div><button click"falg !falg">切换</button><transition name"fade" :enter-to-class"etc"><div v-if"falg&quo…

【开源服务框架】Dubbo

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理Java面试中开源服务框架Dubbo会涉及到的知识点 &#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一…

C++标准库容器类——string类

引言 在c中&#xff0c;string类的引用极大地简化了字符串的操作和管理&#xff0c;相比 C 风格字符串&#xff08;char*或cahr[]&#xff09;&#xff0c;std::string 提供了更高效和更安全的字符串操作。接下来让我们一起来深入学习string类吧&#xff01; 1.string 的构造…

sqli-lab靶场学习(三)——Less8-10(盲注、时间盲注)

Less8 第八关依然是先看一般状态 http://localhost/sqli-labs/Less-8/?id1 然后用单引号闭合&#xff1a; http://localhost/sqli-labs/Less-8/?id1 这关的问题在于报错是不显示&#xff0c;那没办法通过上篇文章的updatexml大法处理。对于这种情况&#xff0c;需要用“盲…

【C++笔记】C++编译器拷贝优化和内存管理

【C笔记】C编译器拷贝优化和内存管理 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】C编译器拷贝优化和内存管理前言一.对象拷贝时的编译器优化二.C/C内存管理2.1练习2.2 C内存管理方式2.3 operator new与operator…

线程池动态设置线程大小踩坑

在配置线程池核心线程数大小和最大线程数大小后&#xff0c;如果调用线程池setCorePoolSize方法来调整线程池中核心线程的大小&#xff0c;需要特别注意&#xff0c;可能踩坑&#xff0c;说不定增加了线程让你的程序性能更差。 ThreadPoolExecutor有提供一个动态变更线程池核心…

.bixi勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复

导言 在当今数字化时代&#xff0c;勒索软件已成为企业和个人面临的重大安全威胁。.bixi勒索病毒作为其中一种新型恶意软件&#xff0c;以其快速加密文件的能力和高效传播机制引发了广泛关注。该病毒不仅能够迅速锁定用户的关键数据&#xff0c;还常常在感染后施加极大的心理压…

【devops】devops-ansible之介绍和基础使用

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

微信公众号文章自动化排版实现思路

文章目录 一、前言1.1 个人写作的痛点1.2 自动化排版工具实现的功能 二、我的文章创作与发布流程三、公众号文章自动化排版实现思路3.1 Typora软件展示3.2 96微信公众号排版平台展示3.3 自动化排版实现思路3.3.1 先构建一个空的文章html模版3.3.2 读取md文章&#xff0c;对内容…

大学生请码住!分享10款AI论文工具搞定论文开题到答辩全过程!

在当今学术研究和论文写作领域&#xff0c;AI工具的出现极大地提高了写作效率和质量。对于大学生来说&#xff0c;这些工具不仅能够帮助他们快速生成高质量的论文初稿&#xff0c;还能进行内容优化、查重和排版等操作。以下是10款值得推荐的AI论文工具&#xff0c;其中特别推荐…

STL-set/multiset关联式容器

目录 一、常见接口 1.0 迭代器 1.1 构造函数 1.2 增删查 1.3 查找和统计 二、multiset 2.1 构造 2.2 查找 2.3 删除 2.4 统计 关联式容器是⽤来存储数据的&#xff0c;与序列式容器不同的是&#xff0c;关联式容器逻辑结构通常是⾮线性结构&#xff0c;两个位置有紧密…

社交电商中“信任”基础与“链动 2+1 模式 O2O 商城小程序”的价值探索

摘要&#xff1a;本文深入探讨了在基于社交的商业模式中&#xff0c;“信任”作为重要基础条件的关键作用。详细分析了在产品同质化日益严重的当下&#xff0c;人与人之间口口相传的宣传方式优势。同时&#xff0c;全面引入“链动 21 模式 O2O 商城小程序”&#xff0c;深入阐述…

Java面试篇-AOP专题(什么是AOP、AOP的几个核心概念、AOP的常用场景、使用AOP记录操作日志、Spring中的事务是如何实现的)

文章目录 1. 什么是AOP2. AOP的几个核心概念3. AOP的常用场景4. 使用AOP记录操作日志4.1 准备工作4.1.1 引入Maven依赖4.1.2 UserController.java4.1.3 User.java4.1.4 UserService.java 4.2 具体实现&#xff08;以根据id查询用户信息为例&#xff09;4.2.1 定义切面类&#x…

整合多方大佬博客以及视频 一文读懂 servlet

参考文章以及视频 文章&#xff1a; 都2023年了&#xff0c;Servlet还有必要学习吗&#xff1f;一文带你快速了解Servlet_servlet用得多吗-CSDN博客 【计算机网络】HTTP 协议详解_3.简述浏览器请求一个网址的过程中用到的网络协议,以及协议的用途(写关键点即可)-CSDN博客 【…

[数据结构]无头单向非循环链表的实现与应用

文章目录 一、引言二、线性表的基本概念1、线性表是什么2、链表与顺序表的区别3、无头单向非循环链表 三、无头单向非循环链表的实现1、结构体定义2、初始化3、销毁4、显示5、增删查改 四、分析无头单向非循环链表1、存储方式2、优点3、缺点 五、总结1、练习题2、源代码 一、引…

Mysql----索引与事务

1.索引 1.1什么是MYSQL的索引 MySQL官方对于索引的定义&#xff1a;索引是帮助Mysql高效获取数据的数据结构 Mysql在存储数据之外&#xff0c;数据库系统中还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种引用&#xff08;指向&#xff09;表中的数据&…

萤石云平台接入SVMSPro平台

萤石云平台接入SVMSPro平台 步骤一&#xff1a;进入萤石云官网&#xff1a;https://open.ys7.com/ &#xff0c;点右上角的登陆&#xff0c;填写自己的用户名密码&#xff1b; 步骤二&#xff1a;登陆进去后&#xff0c;开发者服务—>我的账号—>应用信息&#xff0c;在…