c++逆天改命进阶--map_set
1.关联式容器
我们已经接触过STL中的部分容器,比如:vector、list、deque、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。
2.键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与
其对应的中文含义。在SGI-STL中关于键值对的定义如下:
3.树形结构的关联式容器
树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。
4.set
- set是按照一定次序存储元素的容器
- 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
- 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
- set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
- set在底层是用二叉搜索树(红黑树)实现的。
注意:
与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
set中插入元素时,只需要插入value即可,不需要构造键值对。
set中的元素不可以重复(因此可以使用set进行去重)。
使用set的迭代器遍历set中的元素,可以得到有序序列
set中的元素默认按照小于来比较
set中查找某个元素,时间复杂度为:log2 N
set中的元素不允许修改(为什么?)
修改之后可能破坏了二叉搜索树的结构
set中的底层使用二叉搜索树(红黑树)来实现。
5.map
- map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
- 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:typedef pair value_type;
- 在内部,map中的元素总是按照键值key进行比较排序的。
- map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
- map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
- multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。
- 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。
- 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。
- multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列。
- multiset底层结构为二叉搜索树(红黑树)。
6.map和set的简单运用
#include <iostream>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;void test_set1()
{set<int> s;s.insert(3);s.insert(1);s.insert(2);s.insert(14);s.insert(36);s.insert(4);s.insert(3);s.insert(3);//set中的值都是唯一的,所以可以起到去重的效果//遍历方式1set<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;//遍历方式2for (const auto& e : s){cout << e << " ";}cout << endl;//检查单词拼写是否正确//思路:把所有单词都放进set的对象中,把每个写出来的单词去set中查一下在不在//在就是正确的,否则就是错误的set<string> strSet;strSet.insert("hello");strSet.insert("happy");strSet.insert("false");strSet.insert("true");strSet.insert("left");strSet.insert("right");for (auto e : strSet){cout << e << " ";}cout << endl;//set<string>::iterator ret = strSet.find("happy");set<string>::iterator ret = strSet.find("happ");if(ret != strSet.end()){cout << "找到了" << endl;}else{cout << "找不到了" << endl;}}
void test_set2()
{set<int> s;s.insert(3);s.insert(1);s.insert(2);s.insert(14);s.insert(36);s.insert(4);s.insert(3);s.insert(3);//先查找,找到了就删除auto pos = s.find(4);if (pos != s.end()){s.erase(pos);}如果没找到直接删除就会报错//pos = s.find(40);//s.erase(pos);s.erase(40);//这样写 在就删除,不在就不处理也不会报错for (auto e : s){cout << e << " ";}cout << endl;
}void test_set3()
{//multiset允许键值冗余,使用方法和set基本一致//就下面的几个地方有差异multiset<int> s;s.insert(3);s.insert(1);s.insert(2);s.insert(14);s.insert(36);s.insert(4);s.insert(3);s.insert(3);//排序不会去重 允许键值冗余multiset<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;//find查找val有多个的时候,找到的是中序遍历的第一个multiset<int>::iterator pos = s.find(3);while (*pos == 3){cout << *pos << " ";//会将3个3都打印出来pos++;}cout << endl;cout << s.count(3) << endl;//统计3的个数cout << s.count(1) << endl;s.erase(3);//会将所有的3全部删掉it = s.begin();while (it != s.end()){cout << *it << " ";it++;}}
void test_map1()
{map<int, double> m;//插入方式1:调用pair的构造函数,构造一个匿名对象进行插入m.insert(pair<int, double>(1, 1.1));m.insert(pair<int, double>(2, 2.2));m.insert(pair<int, double>(3, 3.3));m.insert(pair<int, double>(4, 4.4));m.insert(pair<int, double>(5, 5.5));//插入方式2 调用函数模板//好处:不需要声明模板参数,让函数模板自己推演,用起来更方便m.insert(make_pair(6, 6.6));//map的遍历map<int, double>::iterator it = m.begin();while (it != m.end()){//cout << (*it).first << ":" << (*it).second << endl;cout << it->first << ":" << it->second << endl;it++;}map<string, string> dict;dict.insert(make_pair("happy", "开心"));dict.insert(make_pair("good", "好的"));dict.insert(make_pair("world", "世界"));dict.insert(make_pair("hello", "你好"));map<string, string>::iterator dit = dict.begin();while (dit != dict.end()){cout << dit->first << ":" << dit->second << endl;dit++;}}void test_map2()
{map<string, string> dict;dict.insert(make_pair("happy", "开心"));dict.insert(make_pair("good", "好的"));dict.insert(make_pair("world", "世界"));dict.insert(make_pair("hello", "你好"));map<string, string>::iterator dit = dict.begin();while (dit != dict.end()){dit->second.insert(0, "{");dit->second += "}";dit++;}dit = dict.begin();while (dit != dict.end()){cout << dit->first << ":" << dit->second << endl;dit++;}//修改map的value数据auto ret = dict.find("happy");if (ret != dict.end()){string& str = ret->second;str.insert(str.size()-1,"、快乐的");}dit = dict.begin();while (dit != dict.end()){cout << dit->first << ":" << dit->second << endl;dit++;}
}
void test_map3()
{//统计出现次数最多的前3种水果string arr[] = { "苹果","橘子", "香蕉", "苹果", "橘子", "苹果", "草莓" ,"苹果" ,"橘子" ,"香蕉" ,"草莓" };//1.统计次数统计次数的方式1:思路:第一次出现就插入<str,1>,否则就++次数//map<string, int> countMap;//for (const auto& str : arr)//{// map<string, int>::iterator ret = countMap.find(str);// if (ret != countMap.end())// {// ret->second++;// }// else// {// countMap.insert(make_pair(str, 1));// }// //}统计次数的方式2//map<string, int> countMap;//for (const auto& str : arr)//{// //insert 的返回值是pair<iterator, bool>// pair<map<string, int>::iterator, bool> ret = countMap.insert(make_pair(str,1));// if (ret.second == false)// {// ret.first->second++;//插入失败,说明不是第一次插入,数量++即可// }//}//统计方式3map<string, int> countMap;for (const auto& str : arr){countMap[str]++;}for (auto e : countMap){cout << e.first << ":" << e.second << endl;}
}
struct MapItCompare
{bool operator()(map<string, int>::iterator x, map<string, int>::iterator y){return x->second > y->second;}};
void test_map4()
{//2找出出现次数最多的前三种水果string arr[] = { "苹果","橘子", "香蕉", "苹果", "橘子", "苹果", "草莓" ,"苹果" ,"橘子" ,"香蕉" ,"草莓" };map<string, int> countMap;for (const auto& str : arr){countMap[str]++;}//对所有水果次数排序的思路vector<map<string, int>::iterator> v;map<string, int>::iterator countMapIt = countMap.begin();while (countMapIt != countMap.end()){v.push_back(countMapIt);countMapIt++;}sort(v.begin(), v.end(), MapItCompare());//利用map排序 --拷贝pair数据map<int, string, greater<int>> SortMap;for (auto e : countMap){SortMap.insert(make_pair(e.second, e.first));}//利用set排序--不拷贝pair数据//set<map<string, int>::iterator, MapItCompare> sortSet;//countMapIt = countMap.begin();//while (countMapIt != countMap.end())//{// sortSet.insert(countMapIt);// countMapIt++;//}typedef map<string, int>::iterator M_IT;//利用优先级队列priority_queue< M_IT, vector<M_IT>, MapItCompare> pq;countMapIt = countMap.begin();while (countMapIt != countMap.end()){pq.push(countMapIt);countMapIt++;}}
void test_map5()
{map<string, string> dict;dict.insert(make_pair("left", "左边"));dict.insert(make_pair("left", "剩余"));//插入失败,已经有left了multimap<string, string> mdict;//允许冗余mdict.insert(make_pair("left", "左边"));mdict.insert(make_pair("left", "剩余"));mdict.insert(make_pair("left", "左边"));}
int main()
{//test_set1();//test_set2();//test_set3();//test_map1();//test_map2();//test_map4();test_map5();return 0;
}
7.求前k个高频单词
[692. 前K个高频单词 - 力扣(LeetCode)
class Solution {public:vector<string> topKFrequent(vector<string>& words, int k) {map<string,int> countMap;//先将数据存到map,此时已经进行了去重并计数for(auto e:words){countMap[e]++;}multimap<int, string,greater<int>> sortMap;//利用multimap允许出现同样次数的单词放进去排序for(auto e : countMap){sortMap.insert(make_pair(e.second, e.first));}vector<string> retV;auto it = sortMap.begin();while(k--)//循环k次,取前k个出现次数最多的{retV.push_back(it->second);it++;}return retV;}
};
c++逆天改命进阶--map_set相关推荐
- c++逆天改命进阶--AVLTree
1.AVL树的概念 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下.因此,两位俄罗斯的数学家G.M.Adelson-Vel ...
- c++逆天改命进阶--RedBlackTree
1.红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black. 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其 ...
- c++逆天改命进阶--多态
1.多态的概念 多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态. 举个栗子:比如买票这个行为,当普通人买票时,是全价买票:学生买票时,是半价买票: ...
- c++逆天改命进阶--继承
1.继承 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加功能,这样产生新的类,称派生类.继承呈 ...
- c++逆天改命进阶--哈希表
1.unordered系列关联式容器 在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想. ...
- c++逆天改命进阶--二叉树练习题
1.根据二叉树创建字符串 606. 根据二叉树创建字符串 - 力扣(LeetCode) class Solution {public:void _tree2str(TreeNode* root, st ...
- 我出书了,《逆天改命——程序员成神之路》开源,从业十年大厂技术专家的一百条人生建议,建议收藏
大家好,我是启舰 我有本出版社约稿的书<逆天改命--程序员成神之路>,最终决定放弃出版社合作,开源给大家. 这本书集合了我从业十来年的经验结晶,希望能够帮到大家. 我在上学和工作期间,也总 ...
- 逆天改命,机械飞升:渐冻症科学家拒绝等死,将自己改造成了「半机械人」...
点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送达 来自:机器之心 作为人类的 Scott-Morgan 已经死去,未来的 Scott-M ...
- 哪吒之魔童降世 - 逆天改命,若命运不公,就和它斗到底!
哪吒之魔童降世 昨晚去看了电影<哪吒之魔童降世>,简称 <哪吒>,讲述了哪吒虽"生而为魔"却"逆天而行斗到底"的成长经历的故事. 看完电 ...
最新文章
- 第一个Xcode项目 - 代码修改布局约束
- memcached+keepalived+magent高群集
- 【Python】选择Python2还是Python3?
- 燃料电池厂商的市场竞争
- 雅虎JavaScript架构师:网页开发技术安全优先
- 使用js来实现模拟无刷新文件上传。
- Jenkins Pinned Plugins(Jenkins绑定插件)
- mvc actionresult返回各种文件
- 遥感数字图像处理——第五章——辐射校正
- php获取m3u8的地址,如何获取各大平台的播放地址(获得优酷的m3u8播放地址)为例...
- WEB安全(十六)单点登录的基本实现
- (四)拒绝服务–TearDrop 攻击
- 深圳绿道最全资料合集
- nyoj453 小珂的烦恼 (set容器)
- 2022年龙岩市高新技术企业奖励补贴,高企网上申报流程是什么?
- 初级会计只刷题能行吗?
- 在通信设备商工作那几年技术上的得与失
- 计算机视觉——图像理解简介
- 【啃书C++Primer5】-c++有些理论基础需要了解,墙裂建议看看原书,有太多细节需要注意了
- 对飚小型机 英特尔发布至强E7 v4系列产品
热门文章
- 看考研视频如何屏蔽键盘(锁定键盘)
- 抖音国庆小游戏是如何实现的?带你走近 Cocos
- 苹果手机数据能恢复吗
- centos7 silk转mp3 wav
- 华为S5300系列交换机V100R006SPH019升级补丁
- 小程序内部引导关注公众号实现方法
- 个人用户永久免费,可自动升级版Excel插件,使用VSTO开发,Excel催化剂功能第12波-快速生成、读取、导出条形码二维码...
- c语言机票座位预定系统_c语言编写~~~机票座位预订系统
- 阶的估计I 无穷小量与强函数2 Taylor公式 基本初等函数与三角函数的阶
- 对公账户:企业银行结算账户