学习STL map, STL set之数据结构基础

STL map和set的使用虽不复杂,但也有一些不易理解的地方,如:

 

或许有得人能回答出来大概原因,但要彻底明白,还需要了解STL的底层数据结构。

C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作。vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入、排序、删除、查找等。让用户在STL使用过程中,并不会感到陌生。

C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般的平衡二叉树(有些书籍根据作者姓名,Adelson-Velskii和Landis,将其称为AVL-树),所以被STL选择作为了关联容器的内部结构。本文并不会介绍详细AVL树和RB树的实现以及他们的优劣,关于RB树的详细实现参看红黑树: 理论与实现(理论篇)。本文针对开始提出的几个问题的回答,来向大家简单介绍map和set的底层数据结构。

为何map和set的插入删除效率比用其他序列容器高?

大部分人说,很简单,因为对于关联容器来说,不需要做内存拷贝和内存移动。说对了,确实如此。map和set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。结构图可能如下:

            A
           / /
          B   C
         / / / /
        D  E F  G

因此插入的时候只需要稍做变换,把节点的指针指向新的节点就可以了。删除的时候类似,稍做变换后把指向删除节点的指针指向其他节点就OK了。这里的一切操作就是指针换来换去,和内存移动没有关系。

为何每次insert之后,以前保存的iterator不会失效?

看见了上面答案的解释,你应该已经可以很容易解释这个问题。iterator这里就相当于指向节点的指针,内存没有变,指向内存的指针怎么会失效呢(当然被删除的那个元素本身已经失效了)。相对于vector来说,每一次删除和插入,指针都有可能失效,调用push_back在尾部插入也是如此。因为为了保证内部数据的连续存放,iterator指向的那块内存在删除和插入过程中可能已经被其他内存覆盖或者内存已经被释放了。即使时push_back的时候,容器内部空间可能不够,需要一块新的更大的内存,只有把以前的内存释放,申请新的更大的内存,复制已有的数据元素到新的内存,最后把需要插入的元素放到最后,那么以前的内存指针自然就不可用了。特别时在和find等算法在一起使用的时候,牢记这个原则:不要使用过期的iterator。

为何map和set不能像vector一样有个reserve函数来预分配数据?

我以前也这么问,究其原理来说时,引起它的原因在于在map和set内部存储的已经不是元素本身了,而是包含元素的节点。也就是说map内部使用的Alloc并不是map<Key, Data, Compare, Alloc>声明的时候从参数中传入的Alloc。例如:

map<int, int, less<int>, Alloc<int> > intmap;

这时候在intmap中使用的allocator并不是Alloc<int>, 而是通过了转换的Alloc,具体转换的方法时在内部通过Alloc<int>::rebind重新定义了新的节点分配器,详细的实现参看彻底学习STL中的Allocator。其实你就记住一点,在map和set内面的分配器已经发生了变化,reserve方法你就不要奢望了。

当数据元素增多时(10000和20000个比较),map和set的插入和搜索速度变化如何?

如果你知道log2的关系你应该就彻底了解这个答案。在map和set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。

最后,对于map和set Winter还要提的就是它们和一个c语言包装库的效率比较。在许多unix和linux平台下,都有一个库叫isc,里面就提供类似于以下声明的函数:

void tree_init(void **tree);
void *tree_srch(void **tree, int (*compare)(), void *data);
void tree_add(void **tree, int (*compare)(), void *data, void (*del_uar)());
int tree_delete(void **tree, int (*compare)(), void *data,void (*del_uar)());
int tree_trav(void **tree, int (*trav_uar)());
void tree_mung(void **tree, void (*del_uar)());

许多人认为直接使用这些函数会比STL map速度快,因为STL map中使用了许多模板什么的。其实不然,它们的区别并不在于算法,而在于内存碎片。如果直接使用这些函数,你需要自己去new一些节点,当节点特别多,而且进行频繁的删除和插入的时候,内存碎片就会存在,而STL采用自己的Allocator分配内存,以内存池的方式来管理这些内存,会大大减少内存碎片,从而会提升系统的整体性能。Winter在自己的系统中做过测试,把以前所有直接用isc函数的代码替换成map,程序速度基本一致。当时间运行很长时间后(例如后台服务程序),map的优势就会体现出来。从另外一个方面讲,使用map会大大降低你的编码难度,同时增加程序的可读性。何乐而不为? 

 

为何map和set的插入删除效率比用其他序列容器高?
为何每次insert之后,以前保存的iterator不会失效?
为何map和set不能像vector一样有个reserve函数来预分配数据?
当数据元素增多时(10000到20000个比较),map和set的插入和搜索速度变化如何?

 

转载于:https://www.cnblogs.com/mtcnn/archive/2006/09/08/9410219.html

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

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

相关文章

男科医生到底有多不正经… | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源真是个鬼才&#xff09;赶紧转给了身边有这种经历的朋友↓ ↓ ↓

5张图带你了解Pulsar的存储引擎BookKeeper

Apache BookKeeper是一款企业级存储系统&#xff0c;最初由雅虎研究院研发&#xff0c;在2011年作为Apache ZooKeeper的子项目进行孵化&#xff0c;在2015年1月成为 Apache顶级项目。起初&#xff0c;BookKeeper是一个预写日志(WAL)系统&#xff0c;经过几年的发展&#xff0c;…

筛选装置用c语言编程,一种空壳瓜子筛选装置的制作方法

本实用新型涉及食品机械领域&#xff0c;特别是一种空壳瓜子筛选装置。背景技术&#xff1a;食品机械是指把食品原料加工成食品(或半成品)过程中所应用的机械设备和装置。食品工业是我国国民经济的支柱产业&#xff0c;食品机械是为食品工业提供装备的行业。随着人民生活水平的…

SO_REUSEADDR

转载&#xff1a; http://www.cppblog.com/aa19870406/archive/2012/07/12/183018.html http://www.cnblogs.com/mydomain/archive/2011/08/23/2150567.html 编写 TCP/SOCK_STREAM 服务程序时&#xff0c;SO_REUSEADDR到底什么意思&#xff1f;这个套接字选项通知内核&#xff…

唱响春天

春天&#xff0c;对就是在这个春天我在博客园里注册了这个ID。一直以来都没有在这里写点什么东西&#xff0c;我想在有空的时候是应该写点东西了。昨天看了江苏卫视的一个叫“绝对唱响”的节目&#xff0c;觉得很有意思&#xff0c;有些许感人的场面&#xff0c;有些触动&#…

不止 Windows 10!Windows 7/8 也能免费升级到 Windows 11

起初&#xff0c;微软宣布为 Windows 7、Windows 8 和 Windows 8.1 用户提供的 Windows 10 免费升级于 2016 年结束。Windows 11 免费升级近日&#xff0c;微软表示将继续支持从 Windows 7、Windows 8 和 Windows 8.1 用户免费升级到 Windows 10 或 Windows 11 &#xff0c;只要…

c语言求平衡因子,平衡二叉树(AVL树)的基本操作

0x00、平衡二叉树的定义平衡二叉树(AVL树)是一种特殊的二叉搜索树&#xff0c;只是在二叉搜索树上增加了对"平衡"的需求。假如一棵二叉搜索树&#xff0c;按照“1,2,3,4,5”的顺序插入数据&#xff0c;会发现二叉树甚至变成了一个线性的链表状结构&#xff0c;这样查…

学校老师绝对不会教的方法,让你的孩子拥有一个开挂般的人生!

比勤奋更重要的&#xff0c;是孩子的思维能力。从上幼儿园开始&#xff0c;很多父母很喜欢给孩子报各种兴趣班&#xff0c;比如钢琴班、英语班、乐高班、报各种各样的课程&#xff0c;就是希望孩子具有18般武艺&#xff0c;赢在起跑线上。其实除了外在的能力&#xff0c;不显山…

通过openpctv简单学习opkg安装与生成包的一些过程

http://linuxtoy.org/archives/openpctv-adding-full-tv-functionality-to-htpc.htmlOpenPCTV - 让你的HTPC拥有更全面的电视功能通过linuxtoy了解到openPCTV是使用opkg打包的获得源代码&#xff1a;git clone git://git.code.sf.net/p/openpctv/code openpctv-code下载完后发现…

保证一个用户已选取的记录不被其他用户选取

问题描述&#xff1a;  用ADO访问数据库&#xff0c;从一个表中取一定的记录&#xff08;比如20行&#xff09;&#xff0c;取出后在程序中使用&#xff0c;使用完后删除掉记录&#xff08;不用更新或删除记录&#xff09;。在多用户操作下(每个用户采用相同的操作)&#xff…

解答网友提问:如何构建动态表达式实现高级查询服务

上次我们介绍了"一秒创建高级查询服务"。前天&#xff0c;有网友在公众号后台问我&#xff0c;怎么使用动态表达式&#xff1a;我想应该是客户提出了更高的要求&#xff0c;查询的条件不仅限于大于、小于&#xff0c;更加多样化&#xff0c;需要动态组合成条件&#…

π!到底蕴藏了多少不为人知的秘密?|今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源网络&#xff0c;侵权删&#xff09;赶紧检查一下π里面有没有你的秘密↓ ↓ ↓

23V3有这种C语言表达式吗,数据结构(C语言版第2版_李云清)习题答案2012-12.doc

数据结构(C语言版第2版_李云清)习题答案2012-12.doc第 1 章 绪论1.1 什么是数据结构&#xff1f;【答】&#xff1a;数据结构是指按一定的逻辑结构组成的一批数据&#xff0c;使用某种存储结构将这批数据存储 于计算机中&#xff0c;并在这些数据上定义了一个运算集合。1.2 数据…

动态内表

很多时候我们的alv报表列是动态的不确定&#xff0c;这样的话如果用平时那种办法肯定是不可行的。 最近有个需求刚好是alv动态的报表&#xff0c;所以现学现卖&#xff0c;总结经验一下&#xff1a; 有一般的列是固定的&#xff0c;还有一些列是动态的 必须要定义的语法如下 *存…

.net core 下的分布式事务锁

系统分布式锁的用法公司框架新增功能分布式锁&#xff1a;锁的性能之王&#xff1a;缓存 > Zookeeper > 数据库锁的实现实现原理&#xff1a;核心采用StackExchange.Redis的LockTake方法实现。支持同步获取锁&#xff0c;或者等待直到超时获取锁。/// <summary>///…

困死我了

又是周一,真想回到周六重新睡個大懶覺..提起來就有氣,可惡的施工負責人....困到現在,還沒精神做事情 转载于:https://www.cnblogs.com/LisaLiu/archive/2006/09/25/514132.html

n以内的素数c语言,关于求N以内素数的一点小问题(N小于一亿)

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼我个人觉得第二个可能是因为内存不够的缘故&#xff0c;于是照着网上的办法弄了一个辅助布尔型数组来改进一下&#xff0c;然后就变成这样了……结果是2The total of the primes are: 1代码如下#include#include#define N 10000usi…

刚刚!华为mate30 pro全球首发,三星黯然失色,iPhone11甚至都被吓降价了

全世界只有3.14 % 的人关注了青少年数学之旅众望所归&#xff0c;9月19日&#xff0c;华为在德国慕尼黑发布了Mate30系列。看完发布会&#xff0c;数据汪给大家总结了几个看点&#xff1a;1.全球一样的版本本次华为mate30系列采用的是EMUI 10系统&#xff0c;不会搭载谷歌旗下的…

cocos2d-x 实现跨平台的目录遍历

可能各位看官们有更好的方法&#xff0c;请不吝赐教。 #ifdef _WIN32 #include <io.h> #else #include <unistd.h> #include <stdio.h> #include <dirent.h> #include <sys/stat.h> #endif win32平台引用io.h里面的信息。 主要定义了一个void df…

c语言埃尔米特插值思路,【数学建模算法】(26)插值和拟合:埃尔米特(Hermite)插值和样条插值...

1.埃尔米特(Hermite)插值1.1.Hermite插值多项式如果对插值函数&#xff0c;不仅要求它在节点处与函数同值&#xff0c;而且要求它与函数有相同的一阶、二阶甚至更高阶的导数值&#xff0c;这就是 Hermite 插值问题。本节主要讨论在节点处插值函数与函数的值及一阶导数值均相等的…