说起map和set,想必我们都学过红黑树了吧,map和set就是红黑树的一个应用领域。它的底层就是由红黑树来实现的。下面简单说一下map和set的使用吧。

首先,有一个栗子是这样的,让我们统计出每种水果出现的次数。

我们会想到怎么解决的。关于map,我们知道,当你插入同样的key值时,它就不会将要插入的key值插入到map中。但是,我们还知道,map是有俩个参数的,一个是插入的key值,另一个value可以用来统计key值出现的次数。

关于统计水果次数的问题,我们主要有以下几种方法:

    map<string,int> countMap;string strs[] = {"苹果","香蕉","橘子","苹果","苹果","香蕉"};//1.从头到尾遍历看是否有数组中的值,没有则插入,有则使second++for(int i = 0; i < sizeof(strs)/sizeof(strs[0]); i++){map<string,int>::iterator it = countMap.find(strs[i]);if(it != countMap.end()){it->second++;}else{countMap.insert(make_pair(strs[i],1));}}map<string,int>::iterator it1 = countMap.begin();while(it1 != countMap.end()){cout<<it1->first<<":"<<it1->second<<endl;++it1;}
//2.检测插入的返回值pair<map<string,int>::iterator,bool>的second是否为false来确定pair<map<string,int>::iterator,bool> ret;for(int i = 0; i < sizeof(strs)/sizeof(strs[0]);i++){ret = countMap.insert(make_pair(strs[i],1));if(ret.second == false)ret.first->second++;}map<string,int>::iterator it1 = countMap.begin();while(it1 != countMap.end()){cout<<it1->first<<":"<<it1->second<<endl;++it1;}
//3.直接使用map重载的[]for(int i = 0; i < sizeof(strs)/sizeof(strs[0]);i++){countMap[strs[i]]++;}map<string,int>::iterator it1 = countMap.begin();while(it1 != countMap.end()){cout<<it1->first<<":"<<it1->second<<endl;++it1;}

运行结果:

这里需要注意的几点是:

1.首先使用插入的时候,是需要插入一个pair结构体,因为map底层的value是一个pair结构体,里边成员又有first和second;因此需要使用make_pair来构造insert的参数。
2.在使用第三种方法的时候,我们使用到map重载的operator[],说一下operator[]的函数:
(*((this->insert(make_pair(x,T()))).first)).second
分解一下上边的operator[]的式子:
this->insert(make_pair(x,T())):返回值为pair<iterator,bool>结构体
((this->insert(make_pair(x,T()))).first):表示pair结构体中的first,即指向一个pair结构体的迭代器,此pair结构体中有key和value,也即所谓的first和second
(*((this->insert(make_pair(x,T()))).first)).second:表示取迭代器中指向的pair的second

说到map,我们还有一个multimap,是用来插入冗余的值,比如有相同的key值的时候,对于map而言,它就不会将其插入,而对于multimap而言就会插入。典型的例子为字典,我们英译汉的时候,同一个英语单词代表着不同的意思,这时multimap就会将每一个key值对应的不同的value值都会插入,并且以排好序的方式显示。

1.比如map来显示字典的时候:

typedef map<string,string> Dict;typedef map<string,string>::iterator DictIt;Dict dict;dict.insert(make_pair("left","左边"));dict.insert(make_pair("right","右边"));dict.insert(make_pair("left","剩余"));DictIt it = dict.begin();while (it != dict.end()){cout<<it->first<<":"<<it->second<<endl;++it;}

结果为:

2.用multimap来实现字典的时候:

typedef multimap<string,string> Dict;typedef multimap<string,string>::iterator DictIt;Dict dict;dict.insert(make_pair("left","左边"));dict.insert(make_pair("right","右边"));dict.insert(make_pair("left","剩余"));DictIt it = dict.begin();while (it != dict.end()){cout<<it->first<<":"<<it->second<<endl;++it;}

运行结果:

综上所述,
(1)map和multimap可以通过key来找value,也可通过key排序
(2)当我们查找某个key值的时候,发现有多个相同的key值,此时不知道it该指向哪个pair结构体,这里要说明的是,它将返回中序遍历的第一个key值

验证一下:

typedef multimap<string,string> Dict;typedef multimap<string,string>::iterator DictIt;Dict dict;dict.insert(make_pair("left","左边"));dict.insert(make_pair("right","右边"));dict.insert(make_pair("left","剩余"));DictIt it = dict.begin();it = dict.find("left");dict.erase(it);it = dict.begin();while (it != dict.end()){cout<<it->first<<":"<<it->second<<endl;++it;}

在这里,我们找到一个key值为left的pair,此时删除它后再打印一下发现得出的是比它大的value值。

说完map和multimap后,与之对应的还有set和multiset。set和multiset是用来判断这个值存在或者不存在。其次也可以用来排序。还有一个特点是过滤(去重)。

1.检测其存在或者不存在

void TestSet()
{typedef set<string> MySet;typedef set<string>::iterator MySetIt;MySet myset;string strs[] = {"苹果","香蕉","橘子","西瓜","草莓","樱桃"};for(int i = 0; i < sizeof(strs)/sizeof(strs[0]); i++){myset.insert(strs[i]);}MySetIt it = myset.begin();if(it == myset.find("哈密瓜"))cout<<"哈密瓜存在"<<endl;elsecout<<"哈密瓜不存在"<<endl;cout<<"存在的其他水果为:"<<endl;it = myset.begin();while(it != myset.end()){cout<<*it<<endl;++it;}
}

运行结果:

2.排序和去重

typedef set<int> MySet;typedef set<int>::iterator MySetIt;MySet myset;for(int i = 10; i > 0; i--)myset.insert(i);myset.insert(5);MySetIt it = myset.begin();while(it != myset.end()){cout<<*it<<endl;++it;}

运行结果:

对于过滤来说,就是如果有相同的key值,它就会去掉相同的key,只插入一个到set中。

这里multiset的意义和multimap差不多,也是处理冗余的数据。使用方法类似。

对于map和set的底层是怎么实现的呢。它是通过写的一个红黑树。主要的区别是

里边的value_type的意义,对于map来说,value_type指的是一个pair的结构体,结构体成员为key和value,而对于set来说,value_type指的是key值。
在红黑树中,用了枚举来表示颜色。而在源码的红黑树中使用了bool值来代替红黑俩种颜色
我们还知道,map和multimap,set和multiset也有区别,底层是怎么用红黑树的呢。它是插入的时候分别对红黑树的插入分为唯一插入(insert_unique)和相等插入(insert_equal)(相等插入就是对冗余数据的考虑)。
set的插入:

map中value_type: typedef pair<const Key, T> value_type;
set中value_type: typedef Key value_type;

set的插入:

  typedef  pair<iterator, bool> pair_iterator_bool; pair<iterator,bool> insert(const value_type& x) { pair<typename rep_type::iterator, bool> p = t.insert_unique(x); return pair<iterator, bool>(p.first, p.second);}

map的插入:

pair<iterator,bool> insert(const value_type& x)
{ return t.insert_unique(x); }

multimap的插入:

  iterator insert(const value_type& x) { return t.insert_equal(x); }

multiset的插入:

  iterator insert(const value_type& x) { return t.insert_equal(x);}

还可以进行相关的区间的插入,删除,某个位置的插入删除等操作。

小姿势:

lower_bound : 用来找到比key值大的数
upper_bound : 用来找到比key值大的数

[数据结构]Map和Set相关推荐

  1. Java数据结构Map的常用功能

    Java数据结构-Map 常用功能 添加功能: map.put(key,value); //添加元素或者修改value的值 删除功能 map.remove(key); 根据key的值删除对应value ...

  2. Java中常见数据结构Map之HashMap

    之前很早就在博客中写过HashMap的一些东西: 彻底搞懂HashMap,HashTableConcurrentHashMap关联: http://www.cnblogs.com/wang-meng/ ...

  3. Java数据结构Map遍历和排序

    map结构和list结合很好用,基本的遍历和排序每次都要查一下,用的不熟练,这里汇总下map的基本遍历和排序,参考的代码如下: package com.vip;import java.util.Arr ...

  4. Java中常见数据结构Map之LinkedHashMap

    前面已经说完了HashMap, 接着来说下LinkedHashMap. 看到Linked就知道它是有序的Map,即插入顺序和取出顺序是一致的, 究竟是怎样做到的呢? 下面就一窥源码吧. 1, Link ...

  5. Java数据结构Map List Set及Queue相关的类图

    闲来无事,把util包中相关的数据结构的类图及其关系画了一下,给大家分享一下. 总览图:  Map:  List and Set: Queue: 再分享一下我老师大神的人工智能教程吧.零基础!通俗易懂 ...

  6. 53 - leetcode 1. 两数之和 数据结构map类

    /*数据结构类,map 一对一关系类 两者 结构不多 可以用空间 明示了vector.size 返回类型 */ class Solution {public:vector<int> two ...

  7. cf519D . A and B and Interesting Substrings 数据结构map

    题意: 已知26个小写字母有各自的权值(正,负,或0) 现在给出一个字符串,长度<=1e5 问这个字符串有多少个子串满足: 开头的字母和结尾的字母一样 字符串除了开头和结尾的字母外,其余的字母的 ...

  8. golang数据结构初探之字典map

    Map Go语言的map底层使用Hash表实现的 特性预览 操作方式 初始化 map分别支持字面量初始化和内置函数make()初始化 字面量初始化 func MapInit() {m := map[s ...

  9. java29:Map

    数据结构: Map         Map 不是Collection的子类 Map 接口定义的集合包含两部分 key-value 以键值的形式保存元素 可以把map看作一个两列多行的表格 根据内部实现 ...

最新文章

  1. 青藏高原matlab掩膜,1982~2000年青藏高原地表反照率时空变化特征
  2. div+css+theme
  3. c语言while可以改为when,控制流:if、when、for、while
  4. 地图库地之图地图窝_「方舆」秦朝地图及行政区划
  5. 错误记录--更改tomcat端口号方法,Several ports (8005, 8080, 8009)
  6. python整数反转_敲代码学Python:力扣简单算法之整数反转
  7. 「附身」马云、恶搞特朗普,AI新应用助你上演「大咖模仿秀」
  8. java弹出提示框jo类_Java JobMeta.getJobLogTable方法代码示例
  9. Shell脚本 批量修改目录下若干文件名
  10. AutoViz:用一行代码自动可视化任何大小的任何数据集
  11. 小米手机解锁bootload教程及常见问题
  12. LTSPICE使用教程:入门指导
  13. 新库上线 | CnOpenData中国各地区方言信息数据
  14. 初学larval 第一篇(大神绕道哦,针对新手友好的一篇)
  15. jeesite 框架搭建与配置(笔记)
  16. HTML+CSS画圣诞树
  17. 从私有云到云的私有部署,重新定义后云时代的企业IT
  18. html a text decoration,你未必知道的CSS小知识:text-decoration属性变成了属性简写
  19. 20155305乔磊2016-2017-2《Java程序设计》第一周学习总结
  20. awk分析话单列子 tcp连接失败率,及失败连接的topN

热门文章

  1. 【CV论文阅读】Rank Pooling for Action Recognition
  2. 实验:sigsuspend(),sigprocmask()
  3. 一位老鸟对 23 种设计模式的有趣见解(转)
  4. struts2自定义拦截器一——模拟登陆权限验证
  5. ASP.NET刷新页面的六种方法
  6. (转)利用MS AJAX 扩展服务器端控件
  7. 微处理器 微型计算机系统,作业答案11微处理器微型计算机和微型计算机系统三者之间.DOC...
  8. VS2019 WPF制作OTA上位机(二)获取bin文件路径
  9. java求最优解库,IPOPT在第二次求解时找到最优解
  10. 【C++grammar】文件I/O流的基本用法