C++ 关联容器-程序员宅基地

技术标签: C++  c++  

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

关联容器map和set

最简单的散列表:数组,arr[key] = value

按关键字有序保存元素 底层实现 查询效率 增删效率
map 关联数组:保存关键字-值对 红黑数 O(log n) O(log n)
set 关键字即值,即只保存关键字的容器 红黑数 O(log n) O(log n)
multimap 关键字可重复出现的map 红黑数 O(log n) O(log n)
multiset 关键字可重复出现的set 红黑数 O(log n) O(log n)
按关键字无序保存元素
unordered_map 用哈希函数组织的map 哈希表 O(1) O(1)
unordered_set 用哈希函数组织的set 哈希表 O(1) O(1)
unordered_multimap 哈希组织的map:关键字可以重复出现
unordered_multiset 哈希组织的set:关键字可重复出现

一、使用

一个值是否存在用set

//单词计数
//       key type,value type
std::map<string, size_t>  word_count;
string word;
while (cin >> word) ++word_count[word]; //若word不在关键字中,自动创建关键字,其值为0
for (const auto &w : word_count)
	cout << w.first << " occurs " << w.second
	     << ( (w.second>1)?" times ":" time " ) << endl;

//使用set
map<string, size_t> word_count;
set<setstring> exclude = {
    "The", "But"};
string word;
while (cin >> word)
// 若word在exclude中find返回指向该元素的迭代器,否则返回尾后迭代器
	if (exclude.find(word) == exclude.end())
		++ word_count[word];

看一个例子:

bool my_tolower(string &wd){
    
    for (auto it = wd.begin(); it != wd.end(); ++it)
        *it = std::tolower(*it); 
    return true;
}
int main(){
    
    vector<string> lst1 ={
    "AVC", "sIdf"},lst2;
    std::copy_if(lst1.begin(), lst1.end(), 
    //泛型算法向谓词传递的是 解引用的迭代器,即引用类型,指向lst1的元素
    //变为小写后,根据谓词返回结果决定是否将该元素 拷贝 到迭代器所指的位置
            std::inserter(lst2, lst2.begin()), my_tolower/*通过该谓词将单词变为小写*/ );
    for (auto c:lst1) cout << c << " "; cout << endl;   //avc sidf
    for (auto c:lst2) cout << c << " "; cout << endl;   //avc sidf
    for (auto it = lst2.begin(); it != lst2.end(); ++it){
    
        *it = "aa";
    }
    for (auto c:lst1) cout << c << " "; cout << endl;  //avc sidf
    for (auto c:lst2) cout << c << " "; cout << endl;  //aa aa
return 0;}

二、关联容器概述

关联容器的迭代器都是双向的

map<string, size_t> wd_count; //空容器
//列表初始化
set<string> exlude = {
    "a", "asdf"};
map<string, string> authors = {
    {
    key:value}, {
    key2:value2}};
vector<int> ivec = {
    1,1,2,2};
set<int> iset(ivec.cbegin(), ivec.end());
multiset<int> miset(ivec.cbegin(), ivec.cend());

要求:
有序容器要求其key必须定义比较的方法,默认用 <

bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs){
    
	return lhs.isbn() < rhs.isbn();
}
std::multiset<Sales_data, decltype(compareIsbn)*> bookstore(compareIsbn);
std::multiset<Sales_data, bool(*)(const Sales_data &,const Sales_data &)> 
			  bookstore(compareIsbn);

在这里插入图片描述

pair类型

标准库类型pair定义在头文件 utility

pair<T1, T2> p;
pair<T1, T2> p(v1, v2);
pair<T1, T2> p={
    v1, v2};
std::make_pair(v1, v2);  /返回一个用v1, v2初始化的pair,pair的类型从v1和v2的类型推断出来
p.first
p.second
p1 relop p2    关系运算符(<<=>>=)

pair<string, int> process(vector<string> &v){
    b
	if (!v.empty())
		return {
    v.back(), v.back().size()}; //列表初始化
	else
		return pair<string, int> () ;       //隐式构造返回值
}

关联容器操作

key_type 此容器类型的关键字类型
mapped_type 每个关键字关联的类型;只适用于map
value_type 对于set,与key_type相同
对于map,为pair<const key_type, mapped_type>

在这里插入图片描述
在这里插入图片描述
一个map的value_type是一个pair, 可以改变pair的值,但是不能改变关键字成员的值
set的迭代器是 const 的

auto map_it = wd_count.cbegin();
while (map_it != wd_count.cend()){
    
	map_it -> first;
	map_it -> second;
	++ map_it;
}

关联容器的关键子是 const 的意味着

vector<int> ivec = {
    2,4,6,8,2,4,6,8};
set<int> set2;
set2.insert(ivec.cbegin(), ivec.ceng());
set2.insert({
    1,3,5,7,9});

wd_count.insert({
    word, 1});
.insert(make_pair(word, 1));
.insert(pair<string, size_t>(word, 1) );
.insert(map<string, size_t>::value_type(word, 1));

在这里插入图片描述

map<string, size_t> word_count;
string word;
while (cin >> word){
    
	auto res = word_count.insert({
    word, 1});
	if (!res.second)
		++  res.first -> second ;
}

multimap<string, string> authors;
authors.insert( {
    "A", "lele"} );
authors.insert( {
    "A", "haha"} );

c.erase(k);    //从c中删除每个关键字为k的元素。返回
c.erase(p);	   //删除迭代器p指定的元素,p必须指向一个真实的元素不能等于c.end()。
			   //返回一个指向p之后元素的迭代器,若p指向c中的尾元素,则返回c.end()
c.erase(b, e); //删除[b,e)范围内的元素

map下标

set 不支持下标

map<string, size_t> word_count;
word_count["Anna"] = 1;

c[key];    //返回左值,若k不在c中,则插入k并初始化值
c.at(key); //访问关键字为k的元素,带参数检查;多k不在c中,抛出out_of_range异常
  • 在word_count中搜索关键字为Anna的元素,未找到
  • 将新关键字-值插入到word_count中,关键字是一个const string,保存Anna,值进行初始化
  • 提取出新插入的元素,并将值1赋予它

访问元素

set<int> iset = {
    0,1,2,3,4,5,6,7,8,9};
iset.find(1);    //返回一个迭代器,指向key == 1 的元素
iset.find(11);   //返回 .end()
iset.count(1);   //return 1
iset.count(11);  /return 0

在这里插入图片描述

string search_item("Alasdf");
auto entries = authors.count(search_item);
auto iter = authors.find(search_item);
while(entries--){
    
	cout << iter->second << endl;
	++iter;
}

for (auto beg = author.lower_bound(search_item), end = authors.upper_bound(search_item);
	beg != end; ++ beg){
    
	cout << beg -> second << endl;
}

for(auto pos = author.equal_range(search_item); pos.first != pos.second; ++pos.first){
    
	cout << pos.first->second << endl;
}

单词转换 map

map<string, string> buildMap(ifstream &map_file){
    
    string line;
    map<string, string> trans_map;
    while (getline(map_file, line)){
    
        istringstream wds(line);
        string key, value;
        wds >> key >> value;
        trans_map[key] = value;
    }
    return trans_map;
}
string& transform(string &wd, map<string, string> &trans_map){
    
    auto res = trans_map.find(wd);
    if (res != trans_map.end())
        return  res -> second;
    else
        return wd;
}
void word_transform(ifstream &map_file, ifstream &input){
    
    auto trans_map = buildMap(map_file);
    string line;
    while (getline(input, line)){
    
        istringstream words(line);
        bool first_wd = true;
        string wd;
        while (words >> wd){
    
            if (first_wd)
                first_wd = false;
            else
                cout << " ";
            cout << transform(wd, trans_map) ;
        }
        cout << endl;
    }
}
int main(){
    
    ifstream map_file("./mapped.txt"), input("./origin.txt");
    word_transform(map_file, input);
return 0;}

无序容器


在这里插入图片描述
无序容器对关键字类型的要求
必须是hashable

size_t hasher(const Sales_data &sd){
    
	return hash<string>()(sd.isbn());
}
bool eqOp(const Sales_data &lhs, const Sales_data *rhs){
    
	return lhs.isbn() == rhs.isbn();
}
using SD_multiset = unordered_multiset<Sales_data, decltype(hasher)*, decltype(eqOp)*>;
//参数是桶大小、哈希函数指针和相等性判断运算符指针
SD_multiset bookstore(42, hasher, eqOp);

如果类中已经定义了 == 运算符,则可以只重载哈希函数:

//使用FooHash生成哈希值;Foo必须有 == 运算符
unordered_set<Foo, decltype(FooHash)*> fooSet(10, FooHash);

总结

  • 关联容器是一个map或是一个set。map保存 key-value对;set只保存关键字
  • 关键字唯一或不唯一
  • 关键字有序或无序

有序容器使用比较函数来比较关键字,从而将元素按顺序存储。默认采用关键字类型的 < 运算符。
无序容器使用关键字类型 == 运算符和一个hash<key_type>类型的对象类组织元素。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/surfaceyan/article/details/124419462

智能推荐

55MySQL高级SQL语句_mysql in select-程序员宅基地

文章浏览阅读1k次。MySQL高级SQL语句_mysql in select

nvidia jetson nano 操作指南-程序员宅基地

文章浏览阅读1.7k次。本文着重讲解如何从头搭建jetson nano开发环境。_nvidia jetson nano

我的AI之路(21)--用Tensorflow object_detection跑PASCAL VOC 2012数据集_tensorflow读取pascal voc-程序员宅基地

文章浏览阅读1.8k次。 PASCAL VOC(Visual Object Classes)http://host.robots.ox.ac.uk/pascal/VOC/竞赛项目提供了用于目标分类识别的图片数据集以及development kit(用于访问数据和标签的MATLAB代码),分四种竞赛:对象分类/识别竞赛(Classification/Detection Competitions) 目标轮..._tensorflow读取pascal voc

基于异步电机的光伏储能三相并网微电网仿真模型(Simulink仿真实现)-程序员宅基地

文章浏览阅读422次,点赞12次,收藏10次。在模型中,需要考虑到光伏发电系统、储能系统和异步电机发电系统的特性,并设计合适的控制策略,以实现系统的稳定运行和对电网的支持。通过仿真模型,可以研究系统在不同工况下的动态特性、稳定性和效率,为光伏储能三相并网微电网系统的设计和优化提供重要的参考和指导。综上所述,基于异步电机的光伏储能三相并网微电网仿真模型研究涉及到光伏发电系统、储能系统和异步电机发电系统的协同运行,以及它们与电网的互动。在这样的系统中,光伏发电系统、储能系统和异步电机发电系统需要协同运行,以实现并网微电网的稳定运行和对电网的支持。

SU-03T语音模块的使用(持续更新)-程序员宅基地

文章浏览阅读1w次,点赞12次,收藏95次。我们在实现各种电路中,肯定会使用到开关这种器件。开关可以是按键,可以是矩阵键盘。但是如果我们用的是语音模块作为开关,可以让自己的产品显得更加高逼格。本博客用于记录本人准备省电子设计大赛过程中使用的SU-03T的语音模块,使用智能公元的开发网页,博客持续更新,小白向。用你的搜索引擎搜索智能公元:智能公元/AIOT快速产品化平台 (smartpi.cn)登录注册什么的在此不详细介绍。A.点击创建产品:B.随便选择一个产品比如什么什么灯具:C.选择纯离线方案,以及SU-03T模组:D.完成各种配置,点击确定,并生_su-03t

robotframework提升篇(三):用例报错后继续执行-程序员宅基地

文章浏览阅读2.8k次,点赞2次,收藏7次。出错后退出在默认情况下,当一个测试用例中的某个关键字返回错误时,这个测试用例就停止执行剩余的关键字。RF会继续执行下一个用例。这么做的好处是节省时间--反正这里出问题要返回来看了,再继续执行剩下的关键字也没有用了。出错后继续执行 但是,有时候,我们却需要执行用例中的所有关键字,例如:要获取更多的出错信息、更改某些全局相关的变量、做teardown或者rollback操作等。这时候,我们...

随便推点

jetpack compose原理解析-程序员宅基地

文章浏览阅读3.4k次,点赞7次,收藏7次。目录jetpack compse原理解析jetpack compse声明式ui开发原理分析整体框架介绍compose LayoutNode布局介绍@Composeable注解实现细节属性更新小结jetpack compse原理解析jetpack compseJetpack Compose是Google在2019 I/O大会上公布开源的一个非捆绑工具包。Jetpack Compose是用于构建原生Android UI的现代工具包。 Jetpack Compose使用更少的代码,强大的工具和直观的Kotl_jetpack compose原理

现在的 Linux 内核和 Linux 2.6 的内核有多大区别?-程序员宅基地

文章浏览阅读1.8k次。这个问题挺大的。2.6 时代跨度非常大,从2.6.0 (2003年12月发布[36]) 到 2.6.39(2011年5月发布), 跨越了 40 个大版本。3.0(原计划的 2.6.40, 2011年7月发布) 到 3.19(2015年2月发布)。4.0(2015年4月发布)到4.2(2015年8月底发布)。总 的来说,从进入2.6之后,每个大版本跨度开发时间大概是 2 - 3 个月。2.6..._linux 内核大小

什么是Sparse Reward_spare reward-程序员宅基地

文章浏览阅读1.4k次。agent学习的过程中,常常无法及时获得回报。就像家长让小朋友写作业,小朋友可能觉得这个是负面的反馈而不去写作业(做作业让我觉得很痛苦qwq),而没有意识到以后会获得的巨大回报:写完作业后成绩提高,考上好大学,成为高富帅,从此走向巅峰赢取白富美...这个一开始的暂时的小的reward 就叫 Sparse Reward如何让agent在Sparse Reward 中拥有更好的学习表现?..._spare reward

Centos7设置1920x1080分辨率_centos7调整屏幕分辨率-程序员宅基地

文章浏览阅读9.5k次,点赞6次,收藏29次。Centos7设置分辨率_centos7调整屏幕分辨率

编译与链接的问题 gcc -fPIC -shared_symbol `g_hall_mode' can not be used when making a-程序员宅基地

文章浏览阅读2.8k次。地址无关代码,在64位下编译动态库的时候,经常会遇到下面的错误/usr/bin/ld: /tmp/ccQ1dkqh.o: relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC提示说需要-fPIC编译,然后在链接_symbol `g_hall_mode' can not be used when making a shared object; recompile

SpringCloud之高可用的分布式配置中心(Spring Cloud Config)(七)-程序员宅基地

文章浏览阅读39次。当服务实例很多时,都从配置中心读取文件,这时可以考虑将配置中心做成一个微服务,将其集群化,从而达到高可用,架构图如下:准备工作继续使用上一篇文章的工程,创建一个eureka-server工程,用作服务注册中心。在其pom.xml文件引入Eureka的起步依赖spring-cloud-starter-netflix- eureka-server,代码如下:<?xml version=...

推荐文章

热门文章

相关标签