欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > c++进阶之----set和map

c++进阶之----set和map

2025/3/10 12:44:56 来源:https://blog.csdn.net/2401_85878549/article/details/145890401  浏览:    关键词:c++进阶之----set和map

一、set的介绍

1.概念

在C++中,std::set 是标准模板库(STL)中的一个关联容器,用于存储唯一的元素,并且这些元素会按照特定顺序自动排序

2.基本特性

1)唯一性std::set 中的元素是唯一的,不允许重复。如果尝试插入重复的元素,插入操作会失败。

2)自动排序std::set 内部会根据元素的值自动排序,排序规则默认是按照元素类型的 < 运算符来比较。也可以通过自定义比较函数来改变排序规则。

3)基于红黑树实现std::set 内部通常使用红黑树(一种自平衡的二叉搜索树)来存储元素,因此插入、删除和查找操作的时间复杂度都是 O(log n),其中 n 是容器中元素的数量。

3.代码运用

由于此处内容较为简单且知识点零碎,我将知识点放到了代码的注释里 

插入、查找的看这里: 

#include<iostream>
#include<set>
using namespace std;
int main()
{// 去重+升序排序set<int> s = { 5,9,3,6,2,3,9,8,7,4,5 };//支持迭代器//set<int>::iterator it = s.begin();auto it = s.begin();while (it != s.end()){cout << *it <<" ";++it;}cout << endl;s.insert(18);s.insert(2);s.insert(4);s.insert(10);//支持范围forfor (auto e : s){cout << e << " ";}cout << endl;//插入一段initializer_list列表值,已经存在的值插入失败s.insert({ 6,9,6,5,10,20,30,35 });for (auto e : s){cout << e << " ";}cout << endl;// 还可以遍历string比较ascll码大小顺序遍历的set<string> sset = { "hello","left","right","haha" };for (auto e : sset){cout << e <<" ";}cout << endl;//与std标准库中的find的对比//std标准库:暴力查找,O(N)auto it1 = find(s.begin(), s.end(),3);//set自带的:类似于二分查找,查找方式类比搜索二叉树,O(logN)auto it2 = s.find(3);return 0;
}

 单个数据删除的内容看这里:

int main()
{set<int> s = { 4,2,6,8,5,3,4,1,2,7 };for (auto e : s){cout << e << " ";}cout << endl;// 删除最小值s.erase(4);for (auto e : s){cout << e << " ";}cout << endl;s.erase(s.begin());    //删除s的第一个元素,不要看你输入元素的顺序!!!for (auto e : s){cout << e << " ";}cout << endl;// 直接删除xint x;cin >> x;int num = s.erase(x);if (num == 0){cout << x << "不存在" << endl;}for (auto e : s){cout << e << " ";}cout << endl;// 直接查找在利用迭代器删除xint y;cin >> y;auto pos = s.find(y);if (pos != s.end()){s.erase(pos);}else{cout << y << "不存在!" << endl;}for (auto e : s){cout << e << " ";}cout << endl;//用count()函数统计z的出现次数,进而判断是否存在int z = 0;cin >> z;if (s.count(z)){cout << x << "在!" << endl;}else{cout << x << "不存在!" << endl;}return 0;
}

 区间数据删除看这里:

int main()
{set<int> s = { 10,60,25,36,92,35,45,56,30,66,77,88,99 };for (auto e : s){cout << e << " ";}cout << endl;// 实现查找到的[itlow,itup)包含[30, 60]区间// 返回 >= 30auto itlow = s.lower_bound(30);// 返回 > 60auto itup = s.upper_bound(60);// 删除这段区间的值s.erase(itlow, itup);for (auto e : s){cout << e << " ";}cout << endl;return 0;
}

二、miltiset的介绍

1.概念

std::multiset 是 C++ STL 中的一个关联容器,用于存储可重复的元素,并且这些元素会根据指定的比较准则自动排序。基本用法跟set差不多,具体见代码示例

2.代码示例

int main()
{//multiset也是在<set>头文件中multiset<int> ms = { 1,2,6,5,3,2,7,8,9,7,2,7 };//迭代器和范围for均支持multiset<int>::iterator it = ms.begin();while (it != ms.end()){cout << *it << " ";it++;}cout << endl;// 相比set不同的是,x可能会存在多个,find查找中序的第一个int x;cin >> x;auto pos = ms.find(x);while (pos != ms.end() && *pos == x){cout << *pos << " ";++pos;}cout << endl;//相比set不同的是,count会返回x的实际个数cout << ms.count(x)<<endl;// 相比set不同的是,erase给值时会删除所有的xms.erase(x);for (auto e : ms){cout << e << " ";}cout << endl;return 0;
}

三、map的介绍

1.概念

在C++中,std::map 是一个非常强大的容器,属于标准模板库(STL)的一部分。它是一个基于红黑树实现的关联容器,用于存储键值对(key-value),并且保证键的唯一性。

2.基本特性:

1)键值对存储std::map 存储的是键值对,每个键(key)唯一,通过键可以快速访问对应的值(value)。

2)有序性std::map 是有序的,它会根据键的值自动排序。默认情况下,它使用键的 < 操作符来比较键的大小。

3)基于红黑树std::map 内部是通过红黑树实现的,因此插入、删除和查找操作的时间复杂度都是 O(log n)

3.代码示例

3.1 pair 的介绍

在C++中,std::pair 是一个非常实用的模板类,用于将两个不同类型的数据组合在一起。它属于标准模板库(STL)的一部分,通常用于需要同时处理两个相关数据的场景。

std::pair 提供了两个成员变量:

  • first:存储第一个数据。

  • second:存储第二个数据。

3.2 插入部分

#include<iostream>
#include<map>
using namespace std;
int main()
{map<string, string> m;//c++98//方法一pair<string, string> p1("left", "左边");m.insert(p1);//方法二m.insert(pair<string, string>("right", "右边"));//方法三m.insert(make_pair("up", "上"));//c++11//方法四m.insert({ "down","下" });//map<string, string>::iterator it = m.begin();auto it = m.begin();while (it != m.end()){cout << it->first << " " << it->second << endl;//实际上是这样的,重载->,为了可读性,省略一个->//cout << it.operator->()->first << " " << it.operator->()->second << endl;it++;}cout << endl;return 0;
}

插入有一个点值得注意一下: 如果插入的“键值对”在原map中已经有了,则本次插入失败,即key相同,插入失败,value相同,可以插入

我们看如下示例:

运行结果如下: 

四、运用

map这个数据结构是具有映射性质的,很多具有关联的东西都可以用map来解决,这里我们以计次问题为例,来感受一下map的妙处所在!

1.水果计次问题

现在我们给出一些水果,需要统计一下次数,这里给出代码示例

int main()
{string arr[] = { "苹果", "西瓜", "香蕉", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };map<string, int> cmap;for (auto& e : arr){auto it = cmap.find(e);if (it == cmap.end())    //证明之前插入的没有这个水果,我现在要插入{cmap.insert({e,1});}else  //证明之前插入过这个水果了,次数增加一次即可{it->second++;}}for (auto e : cmap){cout << e.first << " " << e.second << endl;}return 0;
}

这种方法是大家都能想到的,但是可能代码要写好长,感觉费时间,因此我们改进一下

 2.[ ]的介绍

std::map[] 运算符是一种非常重要的成员函数,用于访问或插入元素。

1)如果 key 已经存在于 map 中,[] 运算符会返回对应键的值的引用。

2)如果 key 不存在,[] 运算符会插入一个新的键值对,键为 key,值为 ValueType 的默认构造值(例如,如果 ValueTypeint,则默认值为 0),并返回这个新值的引用。

3.【】的应用

	map<string, string> dict;// 插入(基本不会这样用)dict["left"];// 插入+修改dict["up"] = "上";for (auto e : dict){cout << e.first << " " << e.second << endl;}cout << endl;// 修改dict["left"] = "左边";// 查找,输出对应的值cout << dict["left"] << endl;cout << dict["up"] << endl;

运行结果如下 

4.代码更改

int main()
{string arr[] = { "苹果", "西瓜", "香蕉", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };map<string, int> cmap;for (auto e : arr){cmap[e]++;}for (auto e : cmap){cout << e.first << " " << e.second << endl;}return 0;
}

说明:在上述代码中,如果我的水果已经存在了,那么【】会返回对应水果(键)的次数(值)的引用,并通过++完成自增,如果我的水果在之前是没有出现过的,那cmap中会插入一个新的键值对,键为 水果名称,值为 次数,并返回这个新值的引用,在通过++完成自增计数

我们可以在插入几个水果试一试:

	pair<map<string, int>::iterator, bool>  r1 = cmap.insert({ "草莓", 1 });pair<map<string, int>::iterator, bool>  r2 = cmap.insert({ "西瓜", 1 });pair<map<string,int>::iterator, int> r3 = cmap.insert({ "蓝莓",10 });for (auto e : cmap){cout << e.first << " " << e.second << endl;}

 五、multimap

multimap与map的区别我们可以类比mutiset和set的区别,这里我们不多说了,直接看一下代码!

int main()
{map<string, string> ant;ant.insert({ "black","white" });ant.insert({ "dirty","clean" });ant.insert({ "dirty","tidy" });ant.insert(pair<string, string>("dirty", "neat"));for (auto e : ant){cout << e.first << "<->" << e.second << endl;}cout << endl;multimap<string, string> mant;mant.insert({ "black","white" });mant.insert({ "dirty","clean" });mant.insert({ "dirty","tidy" });mant.insert(pair<string, string>("dirty", "neat"));//以上两种方式都可以插入,但个人更倾向于隐式类型转换(第一种)for (auto e : mant){cout << e.first << "<->" << e.second << endl;}return 0;
}

 结果如下:

下面这个大家看一下就好,这里不在多说了

int main()
{std::multimap<char, int> mymm;mymm.insert(std::pair<char, int>('a', 10));mymm.insert(std::pair<char, int>('b', 20));mymm.insert(std::pair<char, int>('b', 30));mymm.insert(std::pair<char, int>('b', 40));mymm.insert(std::pair<char, int>('c', 50));mymm.insert(std::pair<char, int>('c', 60));mymm.insert(std::pair<char, int>('d', 60));std::cout << "mymm contains:\n";for (char ch = 'a'; ch <= 'd'; ch++){std::pair <std::multimap<char, int>::iterator, std::multimap<char, int>::iterator> ret;ret = mymm.equal_range(ch);std::cout << ch << " =>";for (std::multimap<char, int>::iterator it = ret.first; it != ret.second; ++it)std::cout << ' ' << it->second;std::cout << '\n';}return 0;
}

 结果如下:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词