【C++之map的应用】

C++学习笔记---021

  • C++之map的应用
    • 1、map的简单介绍
      • 1.1、基本概念
      • 1.2、map基本特性
    • 2、map的基本操作
      • 2.1、插入元素
      • 2.2、访问元素
      • 2.3、删除元素
      • 2.4、遍历map
      • 2.5、检查元素是否存在
      • 2.6、获取map的大小
      • 2.7、清空map
      • 2.8、基本样例
    • 3、map的基础模拟实现
    • 4、测试用例
      • 4.1、插入和遍历
      • 4.2、查找和删除
      • 4.3、统计次数
      • 4.4、[ ]的插入
      • 4.5、以[ ]再谈统计计数
      • 4.6、equal_range
    • 5、map的性能分析
    • 6、练习题
      • 6.1、前K个高频单词
      • 6.2、单词识别

C++之map的应用

前言:
前面篇章学习了C++对于set和multiset的基本应用的知识认识和了解,接下来继续学习,C++的map等知识。
/知识点汇总/

1、map的简单介绍

1.1、基本概念

在C++中,map是一个标准模板库(STL)中的关联容器,它包含可以重复的键值对集合,其中每个键都是唯一的,并与一个值相关联。
map通常以一个红黑树作为其内部数据结构,这确保了键值对的自动排序和高效的插入、删除和搜索操作。

格式:

std::map<KeyType, ValueType> variable_name;

1.2、map基本特性

1.键唯一性:map中的每个键都是唯一的,不允许有重复的键。
2.自动排序:map中的元素默认按照键的升序进行排序,这是因为它通常使用红黑树来实现。
3.关联容器:通过键来访问对应的值,而不是通过位置或索引。
4.动态大小:map的大小可以根据需要动态地增长或缩小。

2、map的基本操作

2.1、插入元素

方法一:

variable_name.insert(std::pair<KeyType, ValueType>(key, value));

方法二:

variable_name.insert({key, value}); // C++11及更高版本

方法三:

variable_name[key] = value;

2.2、访问元素

方法一:

ValueType& value_ref = variable_name[key];

方法二:

auto it = variable_name.find(key);  
if (it != variable_name.end()) {  ValueType& value_ref = it->second;  // 使用value_ref  
}

2.3、删除元素

方法一:

variable_name.erase(key); // 删除键为key的元素

方法二:

auto it = variable_name.find(key);  
if (it != variable_name.end()) {  variable_name.erase(it);  
}

2.4、遍历map

方法一:使用迭代器

for (auto it = variable_name.begin(); it != variable_name.end(); ++it) {  KeyType key = it->first;  ValueType value = it->second;  // 使用key和value  
}

方法二:基于范围的for循环(C++11及更高版本)

for (const auto& pair : variable_name) {  KeyType key = pair.first;  ValueType value = pair.second;  // 使用key和value  
}

2.5、检查元素是否存在

if (variable_name.find(key) != variable_name.end()) {  // 键存在  
}

2.6、获取map的大小

size_t size = variable_name.size();

2.7、清空map

variable_name.clear();

2.8、基本样例

#include <iostream>  
#include <map>  
int main()
{  std::map<std::string, int> ages;  ages["Alice"] = 30;  ages["Bob"] = 25;  ages.insert({"Charlie", 35});  for (const auto& pair : ages) {  std::cout << pair.first << ": " << pair.second << std::endl;  }  ages.erase("Bob");    return 0;  
}

3、map的基础模拟实现

#include <iostream>  
#include <vector>  
#include <utility> // for std::pair  template <typename Key, typename Value>  
class SimpleMap {  
private:  std::vector<std::pair<Key, Value>> elements;  // 简单的线性搜索函数  size_t findIndex(const Key& key) const {  for (size_t i = 0; i < elements.size(); ++i) {  if (elements[i].first == key) {  return i;  }  }  return std::vector<std::pair<Key, Value>>::npos; // 返回一个特殊值表示未找到  }  public:  // 插入元素  void insert(const Key& key, const Value& value) {  size_t index = findIndex(key);  if (index == std::vector<std::pair<Key, Value>>::npos) {  elements.push_back(std::make_pair(key, value));  } else {  // 如果键已存在,可以选择更新值或不做任何操作(这里选择更新值)  elements[index].second = value;  }  }  // 查找元素  bool find(const Key& key, Value& value) const {  size_t index = findIndex(key);  if (index != std::vector<std::pair<Key, Value>>::npos) {  value = elements[index].second;  return true;  }  return false;  }  // 删除元素  bool erase(const Key& key) {  size_t index = findIndex(key);  if (index != std::vector<std::pair<Key, Value>>::npos) {  elements.erase(elements.begin() + index);  return true;  }  return false;  }  // ... 可以添加其他成员函数,如size(), clear()等  
};  int main() {  SimpleMap<std::string, int> myMap;  myMap.insert("Alice", 30);  myMap.insert("Bob", 25);  int value;  if (myMap.find("Alice", value)) {  std::cout << "Alice's age is " << value << std::endl;  }  myMap.erase("Bob");  // ... 其他操作  return 0;  
}

4、测试用例

4.1、插入和遍历

void test_map1()
{map<string, string> dict;pair<string, string> kv1("sort", "排序");//隐式类型转换dict.insert(kv1);dict.insert(pair<string, string>("left", "左边"));dict.insert(make_pair("right", "左边"));//pair<string, string> kv2 = {"sort", "排序"};//隐式类型转换dict.insert({"insert","插入"});//隐式类型转换//initializer_listmap<string, string> dict2 = { {"sort", "排序"},{"left", "左边"},{"right", "左边"} };map<string, string>::iterator it = dict.begin();//auto it = dict.begin();while(it != dict.end()){//cout << *it << endl;//error//因为pair<string, string> --- 二元的//cout << (*it).first << " : " << (*it).second << endl;//等价cout << it->first << " : " << it->second << endl;//等价原型//cout << it.operator->()->first << " : " << it.operator->()->second << endl;++it;//iterator key不能修改,value可修改//const_iterator key和value都不能修改}cout << endl;//范围forfor (auto& kv : dict){cout << kv.first << ":" << kv.second << endl;}//了解一些C++17的写法 -- 编译器改配置即可//for (auto& [x,y] : dict)//{//	cout << x << ":" << y << endl;//}
}

4.2、查找和删除

void test_map2()
{// 创建一个空的map  std::map<std::string, int> myMap;// 插入元素  myMap["apple"] = 1;myMap["banana"] = 2;myMap["cherry"] = 3;// 遍历map  for (const auto& pair : myMap){std::cout << pair.first << ": " << pair.second << std::endl;}// 查找元素  if (myMap.find("banana") != myMap.end()){std::cout << "Found banana with value: " << myMap["banana"] << std::endl;}else{std::cout << "Banana not found" << std::endl;}// 删除元素  myMap.erase("cherry");// 再次遍历map,以查看"cherry"是否已被删除  for (const auto& pair : myMap){std::cout << pair.first << ": " << pair.second << std::endl;}
}

4.3、统计次数

void test_map3()
{// 统计水果出现的次数string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };map<string, int> countMap;for (auto& e : arr){auto it = countMap.find(e);if (it != countMap.end()){it->second++;}else{//const pair<string,int>& val = {e,1};//pair<string,bool> insert(const value_type& val);//key存在,插入失败,返回->pair<存在的key所在节点的迭代器,flase>//key不存在,插入成功,返回->pair<新插入key所在节点的迭代器,true>countMap.insert({ e,1 });}}for (auto& kv : countMap){//auto& [x, y] = kv;cout << kv.first << ":" << kv.second << endl;}cout << endl;
}

4.4、[ ]的插入

补充:[ ]的底层拆解理解

 V& operator[](const k& key){return (*((this->insert(make_pair(k,mapped_type()))).first)).sencond;}
V& operator[](const k& key)
{//不管是插入成功还是失败,pair中iterator始终指向key所在节点的iteratorpair<iterator, bool> ret = this->insert(make_pair(key, v()));iterator it = ret.first;retrun it->second;
}
void test_map4()
{map<string, string> dict;dict.insert({ "string","字符串" });//插入dict["right"];//插入+修改dict["left"] = "左边";//查找(已存在就是查找)cout << dict["string"] << endl;//修改dict["right"] = "右边";string str;cin >> str;//size_type count(const key_type& k) const;返回个数//计数特定元素的个数if (dict.count(str)){cout << "在" << endl;}else{cout << "不在" << endl;}//multimap与map还有一个区别,multimao没有[]
}

4.5、以[ ]再谈统计计数

void test_map5()
{// 统计水果出现的次数string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };map<string, int> countMap;for (auto& e : arr){countMap[e]++;//插入+修改}for (auto& kv : countMap){//auto& [x, y] = kv;cout << kv.first << ":" << kv.second << endl;}cout << endl;//map<int, string> sortMap;multimap<int, string> sortMap;for (auto& kv : countMap){//数据丢失,本质原因就是multimap和map的区别,因为对于map中已经已经存在的key会被覆盖造成丢失。//sortMap[kv.second] = kv.first;sortMap.insert({ kv.second ,kv.first });}cout << endl;for (auto& kv : sortMap){//auto& [x, y] = kv;cout << kv.first << ":" << kv.second << endl;}cout << endl;
}

4.6、equal_range

equal_range
获取相等元素的范围
返回一个范围的边界,该范围包括容器中具有等价于k的键的所有元素。
它返回一个范围,该范围包含所有与给定键相等的元素。
作用:
equal_range返回一个包含两个迭代器的pair:
first迭代器指向范围中的第一个元素(如果存在)。
second迭代器指向范围之后的第一个元素(即大于给定键的第一个元素),或者如果范围内没有更多的元素,则指向容器的end()。
这个函数的主要用途是当你需要查找一个键的所有出现,或者当你需要在一个有序范围内进行迭代时。

void test_map7()
{map<char, int> mymap;mymap['a'] = 10;mymap['b'] = 20;mymap['c'] = 30;mymap['c'] = 40;mymap['c'] = 50;mymap['f'] = 60;pair<map<char, int>::iterator, map<char, int>::iterator> ret;ret = mymap.equal_range('c');cout << "lower bound points to: ";cout << ret.first->first << " => " << ret.first->second << '\n';cout << "upper bound points to: ";cout << ret.second->first << " => " << ret.second->second << '\n';
}

5、map的性能分析

时间复杂度

1.插入(Insertion):在 std::map 中插入一个元素的时间复杂度是 O(log n),其中 n 是 map 中元素的数量。这是因为红黑树在插入时需要重新平衡树结构以保持其性质。
2.查找(Search):查找一个元素的时间复杂度同样是 O(log n)。在红黑树中,查找操作通过树的层次结构来减少搜索空间,从而实现对数时间复杂度。
3.删除(Deletion):删除一个元素的时间复杂度也是 O(log n)。删除操作同样需要保持红黑树的性质,这可能需要重新平衡树结构。

空间复杂度

std::map 的空间复杂度是线性的,即 O(n),其中 n 是 map
中元素的数量。这是因为每个元素都需要在树中存储一个节点,并且这些节点需要额外的空间来存储键和值,以及指向其子节点的指针。

6、练习题

6.1、前K个高频单词

给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。

思路:用<单词,单词出现次数>构建键值对,然后将vector中的单词放进去,统计每个单词出现的次数

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <utility>
#include <algorithm>using namespace std;class Solution {
public:class KVCompare {public:// 在set中进行排序时的比较规则bool operator()(const pair<string, int>& left, const pair<string, int>& right){return left.second > right.second; // 升序:>  降序:<}};vector<string> topKFrequent(vector<string>& words, int k) {// 用<单词,单词出现次数>构建键值对,然后将vector中的单词放进去,统计每个单词出现的次数map<string, int> countMap;for (auto& e : words){countMap[e]++;}vector<pair<string, int>> v(countMap.begin(), countMap.end());//sort(v.begin(), v.end(), KVCompare());stable_sort(v.begin(), v.end(), KVCompare());vector<string> vRet;for (size_t i = 0; i < k; i++) {vRet.push_back(v[i].first);}return vRet;}
};int main()
{Solution solution;vector<string> words = { "the", "sky", "is", "blue", "the", "sun", "is", "bright", "the", "sun", "is", "shiny", "then", "the", "sky", "became", "even", "more", "blue" };int k = 4;vector<string> topK = solution.topKFrequent(words, k);// 输出结果  cout << "Top " << k << " frequent words are: ";for (const auto& word : topK) {cout << word << " ";}cout << endl;return 0;
}

输出结果:
在这里插入图片描述

6.2、单词识别

输入一个英文句子,把句子中的单词(不区分大小写)按出现次数按从多到少把单词和次数在屏幕上输出来,次数一样的按照单词小写的字典序排序输出,要求能识别英文单词和句号。

思路:思路是先截取单词,通过map记录单词个数,再转存vector进行排序。

#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef pair<string, int> Word;
bool cmp(Word w1, Word w2)
{return w1.second > w2.second;
}
int main()
{map<string, int> mp;string s;while (getline(cin, s)){for (int i = 0, j = 0; i < s.size(); i++){if (s[i] == ' ' || s[i] == '.'){string t = s.substr(j, i - j);if (isupper(t[0]))t[0] = tolower(t[0]);j = i + 1;mp[t]++;}}vector<Word> v(mp.begin(), mp.end());sort(v.begin(), v.end(), cmp);for (int i = 0; i < v.size(); i++)cout << v[i].first << ":" << v[i].second << endl;}return 0;
}

输出结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/832107.shtml

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

相关文章

Flutter笔记:Widgets Easier组件库(11)- 使用提示吐丝

Flutter笔记 Widgets Easier组件库&#xff08;11&#xff09;使用提示吐丝 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this …

【多模态】29、OCRBench | 为大型多模态模型提供一个 OCR 任务测评基准

文章目录 一、背景二、实验2.1 测评标准和结果2.1.1 文本识别 Text Recognition2.1.2 场景文本中心的视觉问答 Scene Text-Centric VQA2.1.3 文档导向的视觉问答 Document-Oriented VQA2.1.4 关键信息提取 Key Information Extraction2.1.5 手写数学公式识别 Handwritten Mathe…

Ubuntu安装配置网络

参考 https://blog.csdn.net/qq_59633155/article/details/131252293https://blog.csdn.net/qq_59633155/article/details/131252293 Ubuntu配置网络 1&#xff0c;查看网络是否连接 终端输入 ping baidu.com 如若成功则如下图所示 如未能成功&#xff0c;则继续按下面步骤…

解决HTTP 403 Forbidden错误:禁止访问目录索引问题的解决方法

解决HTTP 403 Forbidden错误&#xff1a;禁止访问目录索引问题的解决方法 过去有人曾对我说&#xff0c;“一个人爱上小溪&#xff0c;是因为没有见过大海。”而如今我终于可以说&#xff0c;“我已见过银河&#xff0c;但我仍只爱你一颗星。” 在Web开发和服务器管理中&#x…

【精品毕设推荐】基于JSP物流信息网的设计与实现

点击免费下载原文及代码、PPT 摘要 本文讲述了基于JSP物流信息网的设计与实现。该系统使用java语言开发&#xff0c;使系统具有更好的平台性和可扩展性。 该系统实现了用户登录、注册、查询快递信息、快递公司注册成为合作伙伴以及系统管理员对信息进行管理等功能。系统的主…

(三)JVM实战——对象的内存布局与执行引擎详解

对象的内存布局 对象的实例化 对象的创建方式 - new的方式 - Class的newInstance():反射的方式 - Construct的newInstance() - clone:实现Cloneable接口,默认浅拷贝 - 使用反序列化&#xff1a;将二进制流转化为内存对象 创建对象的步骤 - 判断对象对应的类是否加载、链接、初…

You don’t have permission.

The document “XXX” could not be saved. You don’t have permission. 1.查看修改了iOS系统库导致的, 根据提示, 进入到"XXX"文件中, 然后commandz回退/取消 2. Xcode 调试遇到的报错&#xff08;持续更新&#xff09;

18_Scala面向对象编程trait

文章目录 trait1.定义trait2.向类中混入特质2.1没有父类2.2有父类 3.动态混入3.1动态混入查询功能到公司业务中 4.父类&#xff0c;子类&#xff0c;特质初始化优先级5.Scala功能执行顺序6.常用API trait –特质的学习需要类比Java中的接口&#xff0c;源码编译之后就是interf…

练习题(2024/5/3)

1对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&#xff1a; 树中…

(论文阅读-优化器)A Cost Model for SPARK SQL

目录 Abstract 1 Introduction 2 Related Work 3 Background and Spark Basics 4 Cost Model Basic Bricks 4.1 Cluster Abastraction and Cost Model Parameters 4.2 Read 4.3 Write 4.4 Shuffle Read 4.5 Broadcast 5 Modeling GPSJ Queries 5.1 Statistics and S…

QT+网络调试助手+TCP客户端

一、网络调试助手UI界面 编程主要思路&#xff1a; 首先将水平的控件 水平布局 &#xff0c;然后相对垂直的控件 垂直布局 &#xff0c;哪怕是底下的groupBox也需要和里面的内容 水平布局&#xff0c;然后最后框选全部 栅格布局。如果需要界面自适应窗口大小&#xff0c…

【白话机器学习系列】白话特征向量

白话特征向量 一个方阵 A A A 与列向量 v v v 的乘积会生成一个新的列向量。这个新向量通常与原向量有着不同的方向&#xff0c;矩阵在这里代表一个线性变换。然而&#xff0c;某些向量会保持其原始方向。我们称这种向量为矩阵 A A A 的特征向量&#xff08;eigenvector&…

一键 input 苹果 OpenELM,零门槛 Llama 3 教程,40+ 优质模型/数据集/教程,建议收藏!...

现在 AI 行业什么最火&#xff1f; 「大模型」一定仍然排在前三甲的位置。 自从 2022 年底 ChatGPT 面世以来&#xff0c;大模型在各行各业已经带来了太多的惊喜&#xff0c;应用场景愈发丰富&#xff0c;同时也带动了相关底层技术的普及与普适化。尤其是在开源模型繁荣发展之下…

C#核心之面向对象-多态

面向对象-多态 文章目录 1、Vob1、多态的概念2、多态的实现 2、抽象类和抽象方法1、抽象类2、抽象方法 3、接口1、接口的概念2、接口的声明3、接口的使用4、接口可以继承接口5、显示实现接口总结思考 电脑使用USB接口读取数据 4、密封方法 1、Vob 1、多态的概念 多态&#xf…

为什么选择OpenNJet?OpenNJet下一代云原生应用引擎!OpenNJet开发实战!

前言导读 在当今这个数字化转型加速的时代&#xff0c;云原生技术已成为企业和开发者构建现代应用的首选路径。OpenNJet作为新一代云原生应用引擎&#xff0c;在国内外技术社区受到了广泛关注。 本文将深入探讨OpenNJet的特点、优势以及在开发实践中的应用&#xff0c;带您全…

用python画一个正八边形

1 问题 使用turtle库的turtle.fd()函数和turtle.seth()函数绘制一个边长100的正八边形。 2 方法 1、利用for循环解决如何画出图形中相同的八条边的问题。 2、再利用turtle.fd()函数和turtle.seth()函数画出完整的图形。 代码清单 1 import turtleturtle.pensize(2)d0for i in r…

【系统架构师】-选择题(十三)

1、在某企业的营销管理系统设计阶段&#xff0c;属性"员工"在考勤管理子系统中被称为"员工"&#xff0c;而在档案管理子系统中被称为"职工"&#xff0c;这类冲突称为&#xff08; 命名冲突&#xff09;。 同一个实体在同系统中存在不同的命名&am…

智慧旅游引领未来风尚,科技助力旅行更精彩:科技的力量推动旅游业创新发展,为旅行者带来更加便捷、高效和智能的旅行服务

目录 一、引言 二、智慧旅游的概念与特点 &#xff08;一&#xff09;智慧旅游的概念 &#xff08;二&#xff09;智慧旅游的特点 三、科技推动旅游业创新发展 &#xff08;一&#xff09;大数据技术的应用 &#xff08;二&#xff09;人工智能技术的应用 &#xff08;…

【计算机科学速成课】笔记二

笔记一 文章目录 7.CPU阶段一&#xff1a;取指令阶段阶段二&#xff1a;解码阶段阶段三&#xff1a;执行阶段 8.指令和程序9.高级CPU设计——流水线与缓存10.早期编程方式11.编程语言发展史12.编程原理13.算法入门14.数据结构15.阿兰图灵 7.CPU CPU也叫中央处理器&#xff0c;…

在R的 RGui中,使用devtools 安装trajeR

创建于&#xff1a;2024.5.5 文章目录 1. 报错信息2. 尝试使用指定的清华镜像&#xff0c;没有解决3. 找到原因&#xff1a;官网把包删除了4. 尝试从网上下载&#xff0c;然后安装。没有成功5. 使用devtools安装5.1 尝试直接安装&#xff1a;install.packages("devtools&q…