面向对象程序设计——mapの简析

news2024/12/25 15:00:25

1.map的定义

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

1.1map的构造

显式实例化直接构造 

//map
int main()
{
	//显式定义
	map<string, string> dict;
	pair<string, string> key("first", "第一个");
	dict.insert(key);

	return 0;
}

匿名对象构造 

//map
int main()
{
	//显式定义
	map<string, string> dict;
	pair<string, string> key("first", "第一个");
	dict.insert(key);

	//匿名对象
	dict.insert(pair<string, string>("second", "第二个"));

	return 0;
}

 函数模版构造

//map
int main()
{
	//显式定义
	map<string, string> dict;
	pair<string, string> key("first", "第一个");
	dict.insert(key);

	//匿名对象
	dict.insert(pair<string, string>("second", "第二个"));

	//make_pair函数模版直接插入
	dict.insert(make_pair("sort", "排序"));

	return 0;
}

 多参数类型转换

//map
int main()
{
	//显式定义
	map<string, string> dict;
	pair<string, string> key("first", "第一个");
	dict.insert(key);

	//匿名对象
	dict.insert(pair<string, string>("second", "第二个"));

	//make_pair函数模版直接插入
	dict.insert(make_pair("sort", "排序"));

	//C++11支持多参数类型转换
	dict.insert({ "hello","泥嚎" });
	//key相同的情况下,value不相等不会更新,而且key不可以被修改而value可以
	dict.insert({ "hello","泥嚎xixixixixi" });

	//遍历,这里需要显式打印key与value,因为他们是公有的
	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();
	while (it != dict.end())
	{
		//使用.访问
		//cout << (*it).first << ":" << (*it).second << endl;
		
		//使用->访问结构体,这里实际上就是重载了一个->
		//cout << it.operator->()->first << ":" << it.operator->()->second << endl;
		cout << it->first << ":" << it->second << endl;
		++it;
	}

	return 0;
}

 小tips:

1.在map中有一个pair存储key与value,后面我们使用的first就是key,second就是value

2.当新插入一个数据与原来某个数据相同时,如果key相同value不同的情况下,该数据不会更新,且key不可以被修改而value可以被修改

3.通常使用迭代器遍历map时需要显式的使用.或者->访问pair中的first与second,不能直接解引用

2.pair

map底层的红⿊树节点中的数据,使⽤pair存储键值对数据 

pair的代码解释 

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)
   {}
};
template <class T1,class T2>
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
 return ( pair<T1,T2>(x,y) );
}

3.map的增删查 

 3.1插入 

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

这里我们只介绍最常用并且较为重要的一种插入,即在插入后会返回一个pair,注意这里的pair与map底层的pair不同,若插入成功就会返回pair<插入后的key的迭代器,true>,插入失败就返回pair<原来就存在相同key的迭代器,false>,这对后面的operator[]有很大作用

//单个数据插⼊,如果已经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);
//插入
int main()
{
	map<int, string> mymap;
	//1.单个数据插⼊,如果已经key存在则插⼊失败,key存在相等value不相等也会插⼊失败 
    //pair<iterator, bool> insert(const value_type& val);
	mymap.insert({ 1, "first" });
	mymap.insert({ 1,"first_change" });
	auto it = mymap.begin();
	while (it != mymap.end())
	{
		cout << it->first << ":" << it->second << endl;
		it++;
	}

	return 0;
}

 3.2删除

// 删除⼀个迭代器位置的值 
iterator erase (const_iterator position);
// 删除k,k存在返回0,存在返回1 
size_type erase (const key_type& k);
// 删除⼀段迭代器区间的值 
iterator erase (const_iterator first, const_iterator last);
//删除
int main()
{
	map<int, string> mymap;
	mymap.insert({ 1, "first" });
	mymap.insert({ 2,"second" });
	mymap.insert({ 3,"three" });
	mymap.insert({ 4,"four" });
	mymap.insert({ 5,"five" });
	auto it1 = mymap.begin();
	while (it1 != mymap.end())
	{
		cout << it1->first << ":" << it1->second << " ";
		it1++;
	}
	cout << endl;
    //迭代器删除
	mymap.erase(mymap.begin());
	auto it2 = mymap.begin();
	while (it2 != mymap.end())
	{
		cout << it2->first << ":" << it2->second << " ";
		it2++;
	}
	cout << endl;
    //删除指定的key所对应的pair
	mymap.erase(4);
	auto it3 = mymap.begin();
	while (it3 != mymap.end())
	{
		cout << it3->first << ":" << it3->second << " ";
		it3++;
	}
	cout << endl;

	return 0;
}

 3.3查找 

//查找k,返回k所在的迭代器,没有找到返回end() 
iterator find(const key_type& k);
//查找k,返回k的个数 
size_type count(const key_type& k) const;
int main()
{
	//这里使用int()默认初始化为0
	map<string, int> mymap;
	mymap.insert({ "苹果",int() });
	mymap.insert({ "香蕉",int() });
	mymap.insert({ "西瓜",int() });
	mymap.insert({ "菠萝",int() });
	mymap.insert({ "苹果",int() });
	mymap.insert({ "柑橘",int() });
	mymap.insert({ "苹果",int() });
	auto it1 = mymap.begin();
	while (it1 != mymap.end())
	{
		cout << it1->first << ":" << it1->second << " ";
		it1++;
	}
	cout << endl;

	auto it = mymap.find("苹果");
	cout << it->first << ":" << it->second << endl;

	int count = mymap.count("苹果");
	if (count)
	{
		cout << "苹果存在" << endl;
	}
	else
	{
		cout << "苹果不存在" << endl;
	}

	return 0;
}

4.operatpr[]间接实现增删查改

1、如果k不在map中,insert会插⼊k和mapped_type默认值,同时[]返回结点中存储 mapped_type值的引⽤,那么我们可以通过引⽤修改返映射值。所以[]具备了插⼊+修改功能

//operator[]
int main()
{
	map<int, string> mymap;
	mymap.insert({ 1,"first" });

	//1.原来的key不存在->插入+修改
	//key不存在->插入{2,""};
	mymap[2];

	//key不存在->插入+修改{3,"third"};
	mymap[3] = "third";

	return 0;
}

2、如果k在map中,insert会插⼊失败,但是insert返回pair对象的first是指向key结点的迭代器,返回值同时[]返回结点中存储mapped_type值的引⽤,所以[]具备了查找+修改的功能 

//operator[]
int main()
{
	map<int, string> mymap;
	mymap.insert({ 1,"first" });

	//2.原来的key存在->查找+修改
	//key存在->查找,但是必须确定要查找的元素一定存在
	cout << mymap[2] << endl;

	//key存在->修改
	mymap[3] = "third_change";
	cout << mymap[3] << endl;

	return 0;
}

5.multimap和map的差异

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

6.实战代码练习

 138.随机链表的复制

思路解析:

本题的难点就是如何深拷贝一个随机链表,随机链表的定义就是每一个节点都有两个指针,一个指针next指向下一个节点,另一个随机指针指向任意节点,难点就是拷贝这两个指针

不过在学习了map后我们可以使用映射拷贝,即首先创建一个新的链表首先拷贝原链表以及next指针,然后将该链表存储在一个map中,使用每个节点本身当做key,random指针当做value,之后处理拷贝而来的新链表中的random指针,使用map中的key做映射,保证random在拷贝后链表中的相对位置与原链表的相同,最后返回拷贝而来的新链表的头结点

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) 
    {
        map<Node*,Node*> mapNode;
        Node* copyhead = nullptr;
        Node* copytail = nullptr;
        Node* cur = head;

        //拷贝原链表映射到map中并且创建一个新链表拷贝原链表
        while(cur)
        {
            //初始时刻
            if(copytail == nullptr)
            {
                copyhead = copytail = new Node(cur->val);
            }
            else
            {
                //从尾节点开始接入新节点
                copytail->next = new Node(cur->val);
                copytail = copytail->next;
            }
            //映射拷贝到map中
            mapNode[cur] = copytail;
            cur = cur->next;
        }
        
        //处理random指针,copy与cur指针同时运动
        cur = head;
        Node* copy = copyhead;
        while(cur)
        {
            if(cur->random == nullptr)
            {
                copy->random = nullptr;
            }
            else
            {
                //使用映射处理random节点
                copy->random = mapNode[cur->random];
            }
            cur = cur->next;
            copy = copy->next;
        }
        return copyhead;
    }
};

 

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

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

相关文章

在视频上绘制区域:使用Vue和JavaScript实现交互式画布

在数字时代&#xff0c;交互式媒体内容的创建和消费变得越来越普遍。特别是视频内容&#xff0c;它不仅提供了视觉信息&#xff0c;还允许用户与之互动&#xff0c;从而增强了用户体验。本文将介绍如何使用Vue.js框架和JavaScript创建一个交互式组件&#xff0c;该组件允许用户…

Dify创建自定义工具,调用ASP.NET Core WebAPI时的注意事项(出现错误:Reached maximum retries (3) for URL ...)

1、要配置Swagger using Microsoft.AspNetCore.Mvc; using Microsoft.OpenApi.Models;var builder WebApplication.CreateBuilder(args);builder.Services.AddCors(options > {options.AddPolicy("AllowSpecificOrigin",builder > builder.WithOrigins("…

vcruntime140_1.dll无法继续执行代码的6种解决方法

在计算机编程和软件开发中&#xff0c;我们经常会遇到各种错误和问题。其中&#xff0c;vcruntime140_1.dll无法继续执行代码是一个常见的问题。这个问题可能会导致程序崩溃&#xff0c;影响我们的工作进度。因此&#xff0c;了解这个问题的原因以及如何解决它是非常重要的。 …

LinuxC高级作业4

1.整理思维导图 2.统计家目录下.c文件的个数 #!/bin/bash# 初始化计数器 count0# 使用for循环遍历家目录下的所有文件 for file in ~/*; do# 检查文件是否以.c结尾if [[ $file *.c ]]; then# 如果是.c文件&#xff0c;则计数器加1count$((count 1))fi done# 输出结果 echo &…

AURIX单片机示例:开发入门与点亮LED

文章目录 目的模板工程Blinky_LED示例链接总结 目的 这个例程比较简单&#xff0c;主要通过这个例程来介绍 AURIX™ Development Studio(ADS) 和 iLLD 库来开发 AURIX 系列单片机一些入门的内容。一些更为基础的资料等内容可以参考下面文章&#xff1a; 《英飞凌 AURIX TriCo…

解决ArmDS Fast Models 中部分内核无法上电的问题

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决ArmDS Fast Models 中部分内核无法上电的问题。 2、 问题场景 在调用ArmDS的Fast Models中的Cortex-A55的模型&#xff0c;只有Core 0是上电状态&#xff0c;而Core 1处于掉电状态&#xff0c;如图2-1所示&…

使用 HFD 加快 Hugging Face 模型和数据集的下载,解决443报错

Hugging Face 提供了丰富的预训练模型和数据集&#xff0c;而且使用 Hugging Face 提供的 from_pretrained() 方法可以轻松加载它们&#xff0c;但是&#xff0c;模型和数据集文件通常体积庞大&#xff0c;用默认方法下载起来非常花时间。 本文将指导你如何使用 HFD&#xff08…

研一奖学金计划2024/9/23有感

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、需要认真上课的1.应用数理统计&#xff08;开卷考试&#xff09;2.最优化方法&#xff08;开卷考试&#xff09;3.跨文化交际&#xff08;主题演讲20课堂讨…

【C++算法】分治——快排

颜色分类 题目链接 颜色分类https://leetcode.cn/problems/sort-colors/description/ 算法原理 代码步骤 class Solution { public:void sortColors(vector<int>& nums) {int n nums.size();int i 0, left -1, right n;while(i < right){if(nums[i] 0) s…

OpenBayes 教程上新|让虚拟偶像活起来!LivePortrait 实现超逼真表情迁移

过去&#xff0c;使用单一图像生成动态视频效果需要复杂的动画技术和大量的手工操作。特别是在控制眼睛和嘴唇等细节上&#xff0c;耗时且难以实现逼真的同步效果。 LivePortrait 在最新版本中通过精确的画像编辑和视频编辑等功能&#xff0c;极大地简化了这一过程。创作者可以…

spring 代码执⾏ (CVE-2018-1273)

开启环境后访问 IP/users 抓包修改加上 poc &#xff1a; username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("t ouch /tmp/crz")]&password&repeatedPassword 回到kali docker exec -it 自己的id /bin/bash 反弹shel…

[spring]MyBatis介绍 及 用MyBatis操作简单数据库

文章目录 一. 什么是MyBatis二. MyBatis操作数据库步骤创建工程创建数据库创建对应实体类配置数据库连接字符串写持久层代码单元测试 三. MyBatis基础操作打印日志参数传递增删改查 四. MyBatis XML配置文件配置链接字符串和MyBatis写持久层代码方法定义Interface方法实现xml测…

摩尔-彭罗斯伪逆(pinv)

摩尔-彭罗斯伪逆是一种矩阵&#xff0c;可在不存在逆矩阵的情况下作为逆矩阵的部分替代。此矩阵常被用于求解没有唯一解或有许多解的线性方程组。 对于任何矩阵 A 来说&#xff0c;伪逆 B 都存在&#xff0c;是唯一的&#xff0c;并且具有与 A’ 相同的维度。如果 A 是方阵且非…

fastson与jackson重点笔记(包入门)

一&#xff0c;简介 json: JavaScript Object Notation, JS对象简谱。 官网&#xff1a;JSON官网 二&#xff0c;使用场景 网络传输 ​ 描述同样的信息&#xff0c;json相比xml占用更少的空间, <?xml version"1.0" encoding"uTF-8"?> <pers…

S32K3 工具篇8:如何移植RTD MCAL现有demo到其他K3芯片

S32K3 工具篇8&#xff1a;如何移植RTD MCAL现有demo到其他K3芯片 一&#xff0c;文档简介二 &#xff0c;平台以及移植步骤2.1 平台说明2.2 移植步骤2.2.1 拷贝工程并配置2.2.1.1 拷贝工程2.2.1.2 配置工程 2.2.2 EB 工程配置 三&#xff0c; 命令行编译及其结果测试四&#x…

【学习笔记】Linux系统基础知识3 —— cd命令详解

一、前期准备 1.已经正确安装并成功进入Linux系统 说明&#xff1a;本实验采用的 Redhat 系统&#xff08;因系统不一致&#xff0c;可能部分显示存在差异&#xff09; 二、学习内容 提示&#xff1a;学习Linux系统基础命令 cd 命令详解 1、cd命令 1. 功能说明 cd 命令用…

AI模型对比研究员创意

大语言模型可以接受训练&#xff0c;完成许多任务。其中最广为人知的用途之一是作为生成式人工智能&#xff1a;当收到提示或被问到问题时&#xff0c;它们可以生成文本作为答复。例如&#xff0c;公开的大语言模型 ChatGPT 可以根据用户输入生成文章、诗歌和其他文本形式。 任…

kettle从入门到精通 第八十七课 ETL之kettle kettle文件上传

1、kettle本身文件上传功能不是很友好&#xff0c;甚至是不能直接使用&#xff0c;需要调整文件上传接口才可以正常接收到文件&#xff0c;本次讲解内容主要是通过自定义插件解决这个问题。 2、通过springboot 编写简单demo&#xff0c;模拟文件上传&#xff0c;接口支持三个参…

vue-router路由(重定向,嵌套,动态路由匹配,命名,高亮,守卫)

一、前端路由的概念与原理 路由router就是对应关系。分为前端路由和后端路由。 1后端路由 后端路由指的是&#xff1a;请求方式、请求地址与function处理函数之间的对应关系。在node.js中&#xff0c;express理由的基本用法如下&#xff1a; const express require(expres…

Simple Calculator(算法初阶,代码基础,“纯”手撕)

简单计算器&#xff1a;仅适用无括号加减乘除&#xff0c;算法初阶&#xff0c;代码基础&#xff0c;不调库或模块“纯”手撕。 (笔记模板由python脚本于2024年09月22日 12:08:02创建&#xff0c;本篇笔记适合喜欢用python解决实际问题的coder翻阅) 【学习的细节是欢悦的历程】…