当前位置: 首页 > news >正文

【C++】set map 的使用

目录

一. set

二. map

operator[ ]


一. set

底层是搜索树中的红黑树,key 模型

 查找成功,返回节点的迭代器;查找失败返回 end()

返回 key 这个值出现了几次,由于所有元素唯一,有就返回 1,没有就返回 0

#include<iostream>
#include<set>
using namespace std;void test_set1()
{// 排序+去重// 去重原理:一个值已经有了,我们就不插入set<int> s;s.insert(3); s.insert(2); s.insert(4);s.insert(5); s.insert(1); s.insert(5);s.insert(2); s.insert(5);set<int>::iterator it = s.begin();while (it != s.end()){// *it = 10; 报错: “it”: 不能给常量赋值cout << *it << " ";++it;}cout << endl;for (auto e : s) { cout << e << " "; }cout << endl;if (s.find(5) != s.end()) { cout << "找到了" << endl; }if (s.count(5)) { cout << "找到了" << endl; }auto pos = s.find(3);  // O(logN)//auto pos = find(s.begin(), s.end(), 3); // O(N)if (pos != s.end())s.erase(pos);s.erase(30);for (auto e : s) { cout << e << " "; }cout << endl;
}

第 17 行,set 不允许修改:iterator 和 const_iterator 都是 const_iterator

  typedef typename rep_type::const_iterator iterator;typedef typename rep_type::const_iterator const_iterator;

第 30 行是 set 自己的 find
第 31 行是算法库里的 find,用迭代器区间遍例,暴力查找,效率低下


找边界区间

找 >= 的(找下界)

找 > 的(找上界)

void test_set1()
{std::set<int> myset;std::set<int>::iterator itlow, itup;for (int i = 1; i < 10; i++) myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90// 删除[30, 60]itlow = myset.lower_bound(30); // 找 >=30 的最小数itup = myset.upper_bound(60); // 找 >60 的最小数cout << *itlow << endl; // 30cout << *itup << endl; // 70myset.erase(itlow, itup); // 因为这里是[itlow, itup)for (auto e : myset) { cout << e << " "; }cout << endl; // 10 20 70 80 90
}

找相等值的 [ ) 区间

count 和 equal_range 是专门为 multiset 设计的

void test_set2()
{// 排序multiset<int> s;s.insert(3); s.insert(5); s.insert(8);s.insert(7); s.insert(7); s.insert(9);s.insert(7);for (auto e : s) { cout << e << " "; }cout << endl; // 3 5 7 7 7 8 9// 返回中序第一个7auto pos = s.find(7);while (pos != s.end()){cout << *pos << " ";++pos;}cout << endl; // 7 7 7 8 9cout << s.count(7) << endl; // 3auto ret = s.equal_range(7); // 想删掉所有7auto itlow = ret.first; // 返回7auto itup = ret.second; // 返回比7大的值// [itlow, itup)// [7,8)cout << *itlow << endl; // 7cout << *itup << endl; // 8s.erase(itlow, itup);for (auto e : s) { cout << e << " "; }cout << endl; // 3 5 8 9
}

二. map

不能修改 key,可以修改 value
pair 是类模板的结构,map 节点里存数据使用 pair 存的

key 是任意类型都可以,树里面要进行比较大小
如果该类型支持比较大小最好;不支持我们可以自己写仿函数控制


为什么要搞 pair?

namespace key_value
{template<class K, class V>struct BSTreeNode{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;//K _key;//V _value;pair<K, V> _kv;BSTreeNode(const K& key, const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){ }};pair<K, V>& operator*(){return _node->_kv;}pair<K, V>* operator->(){return &_node->_kv;}
}

迭代器最终要重载 operator*,对迭代器解引用,迭代器里面包含节点的指针;C++ 不支持返回俩值
如果是 _key 和 _value,无法返回

要返回多个值,得返回结构


插入的是一个结构对象

5-7 行:调构造函数,构造一个对象
不用把 key 写成 const,自己内部会转换

第 10 行:类 pair 提供了函数模板 make_pair,等价于第 7 行的写法:自动调 pair 的构造

没有效率问题,会被定义为 inline

重点掌握 10.13 行

void test_map1()
{map<string, string> dict;pair<string, string> kv1("insert", "插入");dict.insert(kv1);dict.insert(pair<string, string> ("sort", "排序")); // 匿名对象// C++98dict.insert(make_pair("string", "字符串"));// C++11 多参数的构造函数隐式类型转换dict.insert({ "string", "字符串" });// 隐式类型的转换string str1 = "hello";A aa1 = { 1, 2 };pair<string, string> kv2 = { "string", "字符串" };
}class A // 应该写到上面,这里是嫌挡视野
{
public:A(int a1, int a2):_a1(a1), _a2(a2){ }
private:int _a1;int _a2;
};
void test_map2()
{map<string, string> dict;dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("insert", "插入"));// 不插入,不覆盖;插入过程中,只比较key,value是相同无所谓// key已经有了就不插入了// 查找、删除都只看keydict.insert(make_pair("insert", "xxxx"));//map<string, string>::iterator it = dict.begin();auto it = dict.begin();while (it != dict.end()){//it->first = "xxx"; 报错,_key是const不能修改//it->second = "xxx"; 正确//cout << *it << " "; 报错//cout << (*it).first << ":" << (*it).second << endl;cout << it->first << ":" << it->second << endl;++it;}cout << endl;for (const auto& kv : dict) // 把 *it 给kv{cout << kv.first << ":" << kv.second << endl;}
}

库里没有重载 pair 这个类的流插入、留提取

*it 返回的是 pair

只要 T(里面的数据) 是结构时,要用迭代器重载的->。恰好 map 里面的数据是结构

operator[ ]

void test_map3()
{// 统计次数string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };map<string, int> countMap;//for (auto e : arr)//{//	auto it = countMap.find(e);//	if (it == countMap.end())//	{//		countMap.insert(make_pair(e, 1));//	}//	else//	{//		it->second++;//	}//}for (auto e : arr){countMap[e]++;}for (const auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}
}

以前 string vector deque 的 [ ] 都是用下标,直接返回第 i 个数据的引用(可读可写)
map 的 [ ] 不常规,给 key 返回对应 value 的引用

上面的例子 countMap[e]++,如果 countMap 里面有对应水果,出现一次就++
那第一次是怎么实现的呢?库里面给了


[ ] 通过 insert 实现,借助了 insert 的返回值


1. key 已经在树里面:返回 pair<树里面 key 所在节点的 iterator,false>
2. key 不在树里:返回 pair<新插入 key 所在节点的 iterator,true>

可以看出,insert 还有查找的价值

根据这个模拟实现 operator[ ]V& operator[](const K& key)
{pair<iterator, bool> ret = insert(make(key, V()));return ret.first->second;
}
// countMap[e]++;

若 key 没在树里,调 V 的默认构造,插入成功返回 pair 类型的 ret,拿到 key 迭代器,通过迭代器取到 value 的引用,并返回
第一次:[ ] 是插入,++是修改返回值

若 key 在树里,插入失败返回 pair 类型的 ret,拿到 key 迭代器,通过迭代器取到 value 的引用,并返回

void test_map4()
{map<string, string> dict;dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("insert", "插入"));cout << dict["sort"] << endl; // 查找和读dict["map"];                  // 插入dict["map"] = "映射,地图";     // 修改dict["insert"] = "xxx";       // 修改dict["set"] = "集合";         // 插入+修改for (const auto& kv : dict) // 把 *it 给kv{cout << kv.first << ":" << kv.second << endl;}
}


nultimap 没有提供 [ ],不知道映射哪一个
insert 也不一样,multmap 插入永远成功

哈希用迭代器走不有序,有序是搜索树特有的

本篇的分享就到这里了,感谢观看,如果对你有帮助,别忘了点赞+收藏+关注
小编会以自己学习过程中遇到的问题为素材,持续为您推送文章

http://www.dtcms.com/a/528061.html

相关文章:

  • mormot.net.sock.pas的总体设计分析
  • 上海企业网站制作哪家专业wordpress适合做大型网站吗
  • 建设银行网站怎么看不见余额数字展馆设计
  • 【数组二分查找+数组反转】2022-11-19
  • 【新版发布】标准版PHP v5.6.4正式版,优化部分用户体验
  • Spring Boot3零基础教程,Profile 环境隔离用法,笔记55
  • 【MATLAB例程】二维环境定位,GDOP和CRLB的计算,锚点数=4的情况(附代码下载链接)
  • 英语“近音“易混单词
  • 代码随想录Day62|总结篇
  • 基于VMware和Cent OS的Docker Engine安装与配置
  • 十七、OpenCV中HighGUI模块的介绍和使用
  • 【JVM】详解 编译器原理与优化技术
  • 良好形象的重要性----反思
  • kali抓包流量
  • Python 正则表达式深度解析与实战指南
  • 开源 Linux 服务器与中间件(十二)FRP内网穿透应用
  • 石家庄网站建设王道下拉棒wordpress 类似
  • 基于AT89C52单片机的计算器设计与仿真
  • AI研究-112 DeepSeek-OCR 发展背景 走红原因 新型任务与潜在研究方向 详细分析 附最小运行测试
  • STC32G144K246,高速PWM@240Mhz 运行测试
  • OpenHarmony轻量级内核LiteOS-M技术详解与应用实践
  • hive自定义函数
  • 做新媒体每天必看的网站wordpress exif
  • Elasticsearch从入门到进阶——分布式特性
  • Elasticsearch并发更新冲突问题与解决
  • 数据结构14:查找
  • 怎样做网站模板wordpress用阿里云oss
  • Spring Java配置:告别XML新时代
  • Flutter 异步进阶:Isolate 与 compute 的性能优化实践
  • 太原网站建设模板网页制作的公司怎么注册