c++--------《set 和 map》

news/2024/11/21 14:41:22/

c++--------《set 和 map》

  • 1 set系列的使⽤
    • 1.1 set类的介绍
    • 1.2 set的构造和迭代器
    • 1.3 set重要接口
  • 2 实现样例
    • 2.1: insert和迭代器遍历使⽤样例:
    • 2.2: find和erase使⽤样例:
  • 练习
  • 3.map系列的使用
    • 3.1 map类的介绍
      • 3.1.1 pair类型介绍
    • 3.2 map的数据修改
    • 3.3multimap和map的差异
  • 结束!!!

1 set系列的使⽤

1.1 set类的介绍

• set的声明如下,T就是set底层关键字的类型• set默认要求T⽀持⼩于⽐较,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模版参数• set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第三个参数。• ⼀般情况下,我们都不需要传后两个模版参数。• set底层是⽤红⿊树实现,增删查效率是 ,迭代器遍历是⾛的搜索树的中序,所以是有序的。O(logN)• 前⾯部分我们已经学习了vector/list等容器的使⽤,STL容器接⼝设计,⾼度相似,所以这⾥我  们就不再⼀个接⼝⼀个接⼝的介绍,⽽是直接带着⼤家看⽂档,挑⽐较重要的接⼝进⾏介绍。
template < class T, // set::key_type/value_type类型
class Compare = less<T>, // set::key_compare/value_compare比较函数
class Alloc = allocator<T> // set::allocator_type 
> class set;

1.2 set的构造和迭代器

在这里插入图片描述

~empty(1) 无参构造   set()
~range(2) 迭代器构造 set(InputIterator first,InputIterator second)
~copy(3)  拷贝构造   set(const set& x)
~move(4) 移动构造    set(set&& x)
~initializer list(5) set({1,2,3,4,5})  
// empty (1) ⽆参默认构造
explicit set (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());// range (2) 迭代器区间构造
template <class InputIterator>
set (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& = allocator_type());// copy (3) 拷⻉构造
set (const set& x);// initializer list (5) initializer 列表构造
set (initializer_list<value_type> il,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());// 迭代器是⼀个双向迭代器
iterator -> a bidirectional iterator to const value_type// 正向迭代器
iterator begin();
iterator end();// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

1.3 set重要接口

1: insert (插入元素)

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

2:find(查找元素)

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

3:count (查找元素个数)

//查找val,返回val的个数
size_type count(const value_type& val) const;

4: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);

5:lower_bound 和 upper_bound
返回(upper_bound)的大于val的迭代器
返回(lower_bound)的大于等于val的迭代器

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

2 实现样例

2.1: insert和迭代器遍历使⽤样例:

#include<iostream>
#include<set>
using namespace std;
int main()
{
// 去重+升序排序
set<int> s;
// 去重+降序排序(给⼀个⼤于的仿函数)
//set<int, greater<int>> s;
s.insert(4);
s.insert(3);
s.insert(65);
s.insert(8);
//set<int>::iterator it = s.begin();
auto it = s.begin();
while (it != s.end())
{
// error C3892: “it”: 不能给常量赋值
// *it = 1;//数据不能被修改
cout << *it << " ";
++it;
}
cout << endl;
// 插⼊⼀段initializer_list列表值,已经存在的值插⼊失败
s.insert({ 2,8,3,9 });
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
set<string> strset = { "sort", "insert", "add" };
// 遍历string⽐较ascll码⼤⼩顺序遍历的
for (auto& e : strset)
{
cout << e << " ";
}
cout << endl;
}

【注意】
如果可以改变比较大小顺序 greater降序 ,默认是升序

set<string,greater<string>> strset = { "sort", "insert", "add" };
// 遍历string⽐较ascll码⼤⼩顺序遍历的
for (auto& e : strset)
{
cout << e << " ";
}
cout << endl;
}

在这里插入图片描述

2.2: find和erase使⽤样例:

#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s = { 4,2,7,2,8,5,9 };
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
// 删除最⼩值
s.erase(s.begin());
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
// 直接删除x
int x;
cin >> x;
int num = s.erase(x);
if (num == 0)
{
cout << x << "不存在!" << endl;
}
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
// 直接查找在利⽤迭代器删除x
cin >> x;
auto pos = s.find(x);
if (pos != s.end())
{
s.erase(pos);
}
else
{
cout << x << "不存在!" << endl;
}
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
// 算法库的查找 O(N)
auto pos1 = find(s.begin(), s.end(), x);
// set⾃⾝实现的查找 O(logN)
auto pos2 = s.find(x);
// 利⽤count间接实现快速查找
cin >> x;
if (s.count(x))
{
cout << x << "在!" << endl;
}
else
{
cout << x << "不存在!" << endl;
}
return 0;
}#include<iostream>
#include<set>
using namespace std;
int main()
{
std::set<int> myset;
for (int i = 1; i < 10; i++)
myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90
for (auto e : myset)
{
cout << e << " ";
}
cout << endl;
// 实现查找到的[itlow,itup)包含[30, 60]区间
// 返回 >= 30
auto itlow = myset.lower_bound(30);
// 返回 > 60
auto itup = myset.upper_bound(60);
// 删除这段区间的值
myset.erase(itlow, itup);
for (auto e : myset)
{
cout << e << " ";
}
cout << endl;
return 0;
}

对于erase来说,删除后迭代器会失效

练习

1: 俩个数组的交集

利用set的性质(避免多个数据重复)可以很好解决此问题
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
set<int> s1(nums1.begin(), nums1.end());
set<int> s2(nums2.begin(), nums2.end());
// 因为set遍历是有序的,有序值,依次⽐较
// ⼩的++,相等的就是交集
vector<int> ret;
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
{
ret.push_back(*it1);
it1++;
it2++;
}
}
return ret;
}
};

2:环形链表

 利用接口count可以解决环形链表问题
class Solution {
public:ListNode *detectCycle(ListNode *head) {set<ListNode*> s;ListNode* cur=head;while(cur){if(s.count(cur))//s.count(cur)是判断有无cur的值{return cur;}else s.insert(cur);cur=cur->next;} return nullptr;}
};

随机链表复制

class Solution {
public:Node* copyRandomList(Node* head) {Node* copyhead=nullptr;Node* copytail=nullptr;Node* cur=head;map<Node*,Node*> s;while(cur)//结点映射拷贝{ if(copytail==nullptr){copyhead=copytail= new Node(cur->val);}else{copytail->next=new Node(cur->val);copytail=copytail->next;}s[cur]=copytail;//结点映射 cur->random cur=cur->next;}cur=head;Node* copy=copyhead;
while(cur)//random复制{if(cur->random==nullptr){copy->random=nullptr;}else{copy->random=s[cur->random];}cur=cur->next;    copy=copy->next;}return copyhead;}
};

3.map系列的使用

3.1 map类的介绍

map的声明如下,Key就是map底层关键字的类型,T是map底层value的类型,set默认要求Key⽀持⼩于⽐较,如果不⽀持或者需要的话可以⾃⾏实现仿函数传给第⼆个模版参数,map底层存储数据的内存是从空间配置器申请的。⼀般情况下,我们都不需要传后两个模版参数。map底层是⽤红⿊树实现,增删查改效率是 O(logN) ,迭代器遍历是⾛的中序,所以是按key有序顺序遍历的。

//Key就是map底层关键字的类型,T是map底层value的类型,
template < class Key, // map::key_type
class T, // map::mapped_type
class Compare = less<Key>, // map::key_compare
class Alloc = allocator<pair<const Key,T> > //
map::allocator_type> class map;

3.1.1 pair类型介绍

pair类型是用struct 封装的类,有俩个值key或value
typedef pair<const Key, T> value_type;
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)
{}
template<class U, class V>
pair (const pair<U,V>& pr): first(pr.first), second(pr.second)
{}
};

3.2 map的数据修改

map的构造与set的构造,和接口都差不多

增删查改

Insert
在这里插入图片描述

对于insert的返回值pair<iterator,bool>
(1) single element  给值插入(2) with hint 指定位置插入(3) range 迭代器区间插入(4)initializer list 初始化插入1:对于插入失败,则返回pair<iterator,false>,返回false
2:对于迭代器iterator,返回值iterator是返回插入时的迭代器
// 单个数据插⼊,如果已经key存在则插⼊失败,key存在相等value不相等也会插⼊失败
pair<iterator,bool> insert (const value_type& val);// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert (InputIterator first, InputIterator last);

erase
在这里插入图片描述

对于erase返回值:
1:iterator 返回的是删除的迭代器2:size_type 是返回删除的个数对于参数
1:const iterator position 是 指定区间删除2:const key_type& k 指定值删除3: 迭代器区间删除
// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);// 删除k,k存在返回0,存在返回1
size_type erase (const key_type& k);// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);

find、count
在这里插入图片描述
在这里插入图片描述

iterator find (const key_type& k);
// 查找k,返回k的个数
size_type count (const key_type& k) const;

operator[ ] ()

功能增 查 改
在这里插入图片描述

map的operator【】,给key会返回value,如果key不存在的时候,
1:如果有就会修改second、2: key 不存在就插入

1、如果k不在map中,insert会插⼊k和mapped_type默认值,同时[]返回结点中存储
mapped_type值的引⽤,那么我们可以通过引⽤修改返映射值。所以[]具备了插⼊+修改功能
2、如果k在map中,insert会插⼊失败,但是insert返回pair对象的first是指向key结点的迭代器,返回值同时[]返回结点中存储mapped_type值的引⽤,所以[]具备了查找+修改的功能.

数据修改

前⾯我提到map⽀持修改mapped_type 数据,不⽀持修改key数据,修改关键字数据,破坏了底层搜索树的结构。map第⼀个⽀持修改的⽅式时通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map还有⼀个⾮常重要的修改接⼝operator[],但是operator[]不仅仅⽀持修改,还⽀持插⼊数据和查找数据,所以他是⼀个多功能复合接⼝需要注意从内部实现⻆度,map这⾥把我们传统说的value值,给的是T类型,typedef为mapped_type。⽽value_type是红⿊树结点中存储的pair键值对值。⽇常使⽤我们还是习惯将这⾥的T映射值叫做value。

【注意】

1、如果key已经在map中,插⼊失败,则返回⼀个pair<iterator,bool>对象,返回pair对象first是key所在结点的迭代器,second是false
2、如果key不在在map中,插⼊成功,则返回⼀个pair<iterator,bool>对象,返回pair对象first是新插⼊key所在结点的迭代器,second是true
3、也就是说⽆论插⼊成功还是失败,返回pair<iterator,bool>对象的first都会指向key所在的迭代器
4、那么也就意味着insert插⼊失败时充当了查找的功能,正是因为这⼀点,insert可以⽤来实现operator[]

3.3multimap和map的差异

multimap和map的使⽤基本完全类似,主要区别点在于multimap⽀持关键值key冗余,那么insert/find/count/erase都围绕着⽀持关键值key冗余有所差异,这⾥跟set和multiset完全⼀样,⽐如find时,有多个key,返回中序第⼀个。其次就是multimap不⽀持[],因为⽀持key冗余,[]就只能⽀持插⼊了,不能⽀持修改。

结束!!!

压力不是有人比你努力,而是比你牛叉几倍的人依然在努力。每个优秀的人,都有一段沉默的时光继承就讲到这里谢谢大家的观看!!!


http://www.ppmy.cn/news/1548781.html

相关文章

豆瓣书摘 | 爬虫 | Python

获取豆瓣书摘&#xff0c;存入MongoDB中。 import logging import timeimport requests from bs4 import BeautifulSoup from pymongo import MongoClientheaders {accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,image/apng,*/*;q0.8,…

3. SQL优化

SQL性能优化 在日常开发中&#xff0c;MySQL性能优化是一项必不可少的技能。本文以具体案例为主线&#xff0c;结合实际问题&#xff0c;探讨如何优化插入、排序、分组、分页、计数和更新等操作&#xff0c;帮助你实现数据库性能的飞跃。 一、索引设计原则 索引是MySQL优化的…

【java-Neo4j 5开发入门篇】-最新Java开发Neo4j

系列文章目录 前言 上一篇文章讲解了Neo4j的基本使用&#xff0c;本篇文章对Java操作Neo4j进行入门级别的阐述&#xff0c;方便读者快速上手对Neo4j的开发。 一、开发环境与代码 1.docker 部署Neo4j #这里使用docker部署Neo4j,需要镜像加速的需要自行配置 docker run --name…

Yocto项目 - 层模型与层的全面解析

在嵌入式Linux系统开发中&#xff0c;Yocto项目作为开源工具&#xff0c;已经成为许多开发者的首选。其核心竞争力之一便是其独特的“层模型”。层&#xff08;Layer&#xff09;不仅仅是构建系统的一个组件&#xff0c;它代表了Yocto项目的一种全新架构方式&#xff0c;赋予了…

沃丰科技呼叫中心质检:定义、重要性及选择策略

一、引言 随着客户服务行业的不断发展&#xff0c;呼叫中心成为了企业与客户之间沟通的重要桥梁。而呼叫中心质检&#xff0c;作为保障服务质量的关键环节&#xff0c;越来越受到企业的重视。本文将深入探讨呼叫中心质检的定义、重要性&#xff0c;以及如何选择适合企业需求的…

第一章 Spring Boot快速⼊⻔ —— 构建Spring Boot项目

概览&#xff1a; SpringBoot设计目的是用来简化Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置&#xff0c;可以更加快速便捷地开发Spring项目&#xff0c;在开发过程当中可以专注于应用程序本身的功…

PostgreSQL提取JSON格式的数据(包含提取list指定索引数据)

PostgreSQL提取JSON格式的数据&#xff08;包含提取list指定索引数据&#xff09; ->>, ->, #>, #>> 在PostgreSQL中&#xff0c;处理json或jsonb类型数据时&#xff0c;->>, ->, #> 和 #>> 是非常有用的操作符&#xff0c;它们允许你以…

线性回归Tensorflow实现

简介&#xff1a;本文会讲解一段使用Tensorflow实现线性回归的代码&#xff0c;这些代码中涉及到的一些知识点&#xff0c;会有细致入微的讲解。 本专栏将会在Tensorflow1.14.0版本下&#xff0c;讲解神经网络&#xff0c;希望大家可以多多关注支持。 线性回归Tensorflow实现 …