提高map[key]=value的效率

2023-11-14

当关乎效率时应该在map::operator[]和map-insert之间仔细选择


我们知道 这个表达式 

m[k] = v;  

检查键k是否已经在map里。如果不,就添加上,以v作为它的对应值。如果k已经在map里,它的关联值被更新成v。


举例一:考虑插入一个新值

这个语句
m[1] = 1.50; 


功能上等价于这个:

typedef map<int, Widget> IntWidgetMap;

// 用键1建立新映射入口和一个默认构造的值对象;                        
pair<IntWidgetMap::iterator, bool> result =

m.insert(IntWidgetMap::value_type(1, Widget()));       
// 赋值给新构造的值类型                                                           
result.first->second = 1.50;                                    
 

看下面的代码:

m.insert(IntWidgetMap::value_type(1, 1.50)); 
这与上面的那些代码有相同的最终效果,除了它通常节省了三次函数调用:一个建立临时的默认构造Widget对象,一个销毁那个临时的对象和一个对Widget的赋值操作。那些函数调用越昂贵,你通过使用map-insert代替map::operator[]就能节省越多。                  

上面的代码利用了每个标准容器都提供的value_type typedef。这typedef没有什么特别重要的,但对于map和multimap(以及非标准容器的hash_map和hash_multimap),记住它是很重要的,容器元素的类型总是某种pair。                                     


举例二:考虑更新值

 // 使用operator[]来把k的值更新为v

m[k] = v;                                                              
 

// 使用insert来把k的值更新为v                                                             
m.insert( IntWidgetMap::value_type(k, v) ).first->second = v;              
                                                               
语法本身也许会让你信服地支持operator[],但在这里我们关注于效率,所以我们将忽略它。insert的调用需要IntWidgetMap::value_type类型的实参(即pair<int, Widget>),所以当我们调用insert时,我们必须构造和析构一个那种类型的对象。那耗费了一对构造函数和析构函数,也会造成一个Widget的构造和析构,因为pair<int, Widget>本身包含了一个Widget对象,operator[]没有使用pair对象,所以没有构造和析构pair和Widget。


总结:出于对效率的考虑,当给map添加一个元素时,我们断定insert比operator[]好;而从效率和美学考虑,当更新已经在map里的元素值时operator[]更好。


很容易可以想象一个像这样的调用接口:

 // map的类型 

//KeyArgType和ValueArgtype是类型参数

template<typename MapType,typename KeyArgType, typename ValueArgtype>          
typename MapType::iterator 
efficientAddOrUpdate(MapType& m,const KeyArgType& k,const ValueArgtype& v){
// 找到k在或应该在哪里       

typename MapType::iterator Ib =m.lower_bound(k); 

// 如果Ib指向一个pair,它的键等价于k,更新这个pair的值并返回指向pair的迭代器      

if(Ib != m.end() &&!(m.key_comp()(k, Ib->first))) {                

Ib->second = v;                 
return Ib;                      
        }                                       
        else{
typedef typename MapType::value_type MVT;

// 把pair(k, v)添加到m并返回指向新map元素的迭代器
return m.insert(Ib, MVT(k, v)); 
        }                                       

                                                      
执行一个高效的增加或更新,我们需要能找出k的值是否在map中;如果是这样,那它在哪里;如果不是,它该被插入哪里。这个工作是为low_bound量身定做的,所以在这里我们调用那个函数。确定ower_bound是否用我们要寻找的键找到了一个元素,我们对后半部分进行一个等价测试,一定要对map使用正确的比较函数:通过map::key_comp提供的比较函数。等价测试的结果告诉我们应该进行增加还是更新


如果是更新,代码很直截了当。插入分支更有趣,因为它使用了insert的“提示”形式。结构m.insert(Ib,MVT(k,v))“提示”了Ib鉴别出了键等价于k的新元素正确的插入位置,而且标准保证如果提示正确,那么插入将在分摊的常数时间内发生,而不是对数时间。在efficientAddOrUpdate里,我们知道Ib鉴别出了适当的插入位置,因此insert的调用被保证为是一次常数时间操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

提高map[key]=value的效率 的相关文章

  • docker-compose实现容器任务编排

    项目开发中 往往都需要启动多个容器 容器之间又相互依赖 存在着启动的顺序 docker compose就是可以通过命令控制依次启动容器 容器编排工具可以帮助我们批量地创建 调度和管理容器 帮助我们解决规模化容器的部署问题 Docker 三种

随机推荐

  • PyQt5 按钮Buttons样式设计

    效果截图 PyQt 模型设计 PyQt 设计器截图 ui 源码
  • 存储IOPS指标说明

    二 IOPS 说明 2 1 IOPS Input OutputPer Second IOPS 即每秒的输入输出量 或读写次数 是衡量磁盘性能的主要指标之一 IOPS是指单位时间内系统能处理的I O请求数量 一般以每秒处理的I O请求数量为单
  • 材料阅读 - 四散的安全

    20201005 阅读了三篇与安全相关的文章 这里记录一下 1 以 威胁应对 为中心 看企业信息安全能力建设 这篇文章发表在了很多地方 发表的念头也比较早了 都过了两年了 对企业的安全能力 从架构上 最后到以后的安全产品都进行了介绍 同时也
  • 多态性 - C++中实现运行时多态的方式

    一 概述 C 中的多态性是指同一个函数可以有多种不同的实现方式 并且在运行时根据实际情况进行选择执行 在C 中实现多态有两种方式 静态多态和动态多态 静态多态是指在编译时确定函数的实现 包括函数重载和模板函数 动态多态是指在运行时根据对象的
  • 针对无人机航拍视频中动态背景下的目标检测

    目录 目录 传统目标检测技术 传统目标检测技术 1 帧间差分 通过连续两帧相同位置像素点间的灰度差来确定目标移动 但只适用于静态背景和目标单一条件的目标检测 仅适用于无人机悬停状态下的目标检测 2 背景差分法 通过预先设置背景 然后通过对检
  • “体育游戏第一股”投资未来,望尘科技走向价值兑现周期

    2022年的游戏市场 遗憾以疲弱之势落下帷幕 游戏市场规模与用户数量 均出现了小幅下降 显示出存量市场的典型特征 但与此同时 更多垂直领域的拳头产品 响应市场需求的精品游戏 却屡屡掀起热潮 去年随世界杯而来的 最佳球会 就是一例 最佳球会
  • C# 基础知识 (四).C#简介及托管代码

    暑假转瞬即逝 从10天的支教生活到1周的江浙沪旅游 在这个漫长的暑假中我经历了很多东西 也学到了很多东西 也认识到了很多不足之处 闲暇之余我准备重新进一步巩固C 相关知识 包括C 入门知识 C 并行开发 ASP网站等 这篇文章我介绍的是书籍
  • JS 地址截取 省市区 (含自治区,直辖市,县,自治县)

    方法一 通过js处理 var str 湖北省武汉市江夏区文化大道110号 var str 内蒙古自治区乌兰浩特市二区 var str 重庆市渝中区中兴路 var str 湖北省黄石市阳新县 var str 湖北省宜昌市长阳土家族自治县 va
  • 同步与异步的区别

    同步与异步的区别 最近在学习ajax 而ajax Asynchronous JavaScript and XML 是一种异步的JavaScript和XML技术 鉴于此 就先来了解下同步与异步的思想和区别 一 同步与异步 同步 同步是指一个进
  • LIBSVM入门

    一 引言 LIBSVM提供了多语言 java python和matlab 的SVM实现 可以便捷地处理分类或回归问题 本文记录基于matlab的LIBSVM学习笔记 二 环境搭建 LIBSVM下载链接 https github com cj
  • Vue3 + Element Plus 按需引入 - 自动导入

    文章目录 1 前言 1 1 目的 1 2 最终效果 2 准备工作 3 按需引入 3 1 安装插件 3 2 修改 vite config ts 文件 4 其他 4 1 ElMessageBox 使用时报错 4 1 1 Eslint 报错 El
  • B/S架构和C/S架构的定义和区别(不同点)

    一 B S架构和C S架构的定义 1 B S Browser Server 浏览器和服务器架构 比如百度 微博 淘宝等网站 包含寄户端浏览器 web应用服务器 数据库服务器的软件系统 用户只需要一个浏览器就可以访问服务 系统更新时候 只需要
  • 【操作系统】操作系统知识点总结(秋招篇)

    文章目录 前言 操作系统主要做了哪些工作 进程 线程 协程之间的区别 进程的组成部分 介绍一下进程的PCB 讲一下进程的五态 以及它们的状态转移 用户态和内核态是什么 进程在用户态和内核态之间是如何切换的 讲一下进程之间的通信方式 讲一下进
  • [Unity2D]Tilemap Collider2D只给部分地图瓦片加上Collider的方法

    Unity2D Tilemap Collider2D 给Tilemap中的瓦片网格加上碰撞器 绿色的边框就是碰撞器 需要注意的是 如果给Tilpmap加碰撞器 其整个Tilpmap上的瓦片都会加上碰撞器 在一个Tilpmap上 如果想让部分
  • mongodb监控工具mongostat

    mongostat是mongodb自带的状态检测工具 在命令行下使用 会间隔固定时间获取mongodb的当前运行状态 并输出 常用命令格式 mongostat host 192 168 1 100 27017 uroot p123456 a
  • CreateRemoteThread的使用(转载)

    先解释一下远程进程 其实就是要植入你的代码的进程 相对于你的工作进程 如果叫本地进程的话 它就叫远程进程 可理解为宿主 首先介绍一下我们的主要工具CreateRemoteThread 这里先将函数原型简单介绍以下 CreateRemoteT
  • Android 特许权限白名单

    1 前言 在项目开发中 需求 app中有恢复出厂设置的功能 分解这个需求的时候 第一反应肯定不是第三方app 恢复出厂设置肯定需要有系统权限 属于系统级的app 然后在看手机系统中的功能 恢复出厂设置功能属于设置模块 找到源码阅读 当然是能
  • 2017-7-17 2-2 不使用&&和

    include
  • tomcat下载和配置(简单,详细)

    下载 官网 http tomcat apache org 找到需要的版本 点击download 在download页面 选择需要下载的 分为压缩版和安装版 我比较推荐压缩版 省事解压缩就好 配置 首先 tomcat7 0以上版本不需要配置环
  • 提高map[key]=value的效率

    当关乎效率时应该在map operator 和map insert之间仔细选择 我们知道 这个表达式 m k v 检查键k是否已经在map里 如果不 就添加上 以v作为它的对应值 如果k已经在map里 它的关联值被更新成v 举例一 考虑插入