【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…

.LockBit 3.0勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复

尊敬的读者&#xff1a; 网络安全是现代社会的重要基石&#xff0c;但勒索病毒等网络威胁却不断挑战着我们的防线。.LockBit 3.0作为近期出现的新型勒索病毒&#xff0c;其独特的攻击方式和强大的加密能力引起了广泛关注。本文将深入解析.LockBit 3.0的特点&#xff0c;并给出…

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…

npm 使用总结

npm&#xff08;Node Package Manager&#xff09;是Node.js的包管理器&#xff0c;它允许你安装、更新、删除和管理Node.js应用程序的依赖项。以下是npm的一些使用总结&#xff1a; 安装npm&#xff1a;npm通常与Node.js一起安装。你可以从Node.js的官方网站下载适合你操作系统…

【精品毕设推荐】基于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;

基于频率比模型采用arcgis的滑坡易发性评估

目录 参考视频:频率比模型地形因子处理shp文件与缓冲区地理校准填补缺失值利用模糊隶属度进行归一化易发性结果出图处理:参考视频: 1. ArcGIS滑坡易发性评价_哔哩哔哩_bilibili 2. landslides susceptibility assessemnt using frequently ration approach /滑坡敏感性制图…

四工位自动攻丝机自动控制

/**************进料检测********************/ /***缺料无限次循环 手动退出 超时报警*******/ void check_Pon() { zstatus0; //缺料报警计数器归零 Signauto1; //…

android native开发

framwork 一些重要的流程都是要放到native中做的 原因也很简单&#xff0c;效率&#xff0c;尤其是针对性能优化方面的&#xff0c;更离不开native开发 目前针对native开发也回顾下&#xff0c;总结下经验 1 jni开发有两种&#xff0c;app端一般是静态模式&#xff0c;要有jav…

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…

qwen-vl微调

1.数据格式转换 模版格式&#xff1a; [{"id": "identity_0","conversations": [{"from": "user","value": "你好"},{"from": "assistant","value": "我是Qwen-V…

C语言共享内存

windows下实现共享内存 进程A写入共享内存&#xff1a; #include <stdio.h> #include <windows.h>int main() {// 创建或打开共享内存对象HANDLE hMapFile CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,4096, // 内存大小&#xff0c;这里为4…

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

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

在Ubuntu 24.04 LTS (Noble Numbat)上搭建Kubernetes集群

准备工作 系统准备 主机和IP地址准备 ​编辑安装步骤 安装前准备 关闭防火墙 设置服务器时区 关闭 swap 分区 关闭SELinux 配置hosts配置文件 转发 IPv4 并让 iptables 看到桥接流量 每台机器设置hostname 安装容器运行时 安装Kubernetes 配置并安装apt包 初始…

Android Studio学习笔记——数据库存储

Android Studio学习笔记——数据库存储 6.1持久化技术简介6.2 文件存储将数据存储到文件中从文件中读取数据 6.3 SharedPreferences存储6.3.1 将数据存储到是SharedPreferences中6.3.2 从SharedPreferences中读取数据6.3.3 实现记住密码功能 6.4 SQLite数据库存储6.4.1 创建数据…