C++|树形关联式容器(set、map、multiset、multimap)介绍使用

目录

一、关联式容器介绍

1.1概念

1.2键值对

1.3树形结构的关联式容器

 1.3.1pair模板介绍 

1.3.2make_pair的介绍 

二、set的介绍和使用

2.1set介绍

2.2set使用

 2.2.1构造 

2.2.2容量

2.2.3修改

三、map的介绍和使用 

 3.1map介绍

 3.2map使用

 3.2.1构造

3.2.2容量

3.2.3修改

四、multiset和multimap简单介绍使用


一、关联式容器介绍

1.1概念

我们之前学过的STL中的部分容器,比如:string、vector、list、deque等。这些都是序列式容器,他们都是线性序列的数据结构,里面存储的是元素本身。

关联式容器:也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key,value>结构的键值对,在数据检索时比序列式容器效率更高

1.2键值对

在搜索二叉树中的kv模型已经介绍过了键值对了,它是用来表示具有一一对应关系的结构,该结构中包含两个成员变量,key和value,key代表键值,value表示与key对应的信息。比如:建立英汉词典互译、统计value出现的次数 

1.3树形结构的关联式容器

 为了更好的管理数据,STL设计了两种不同结构的管理式容器:树形结构与哈希结构。树形结构的关联式容器主要有四种:map、set、multimap、multiset。他们的底层采用都是平衡搜索树(即红黑树)来实现,容器中的元素是有序的序列。那么接下来在学习他们的用法前,先介绍一下pair,以方便后续理解set,map使用。在下一章节,将会模拟实现他们。

 1.3.1pair模板介绍 

pair有两个模板参数,pair类中有两个元素first,second,分别为T1,T2类型。其中T1被typedef成first_type,T2被typedef成second_type。其中,元素first,second可以修改。对于set,虽然其key值不存在pair当中,但有接口的返回值类型是pair类型。对于map,其值key和value存放在pair中。

函数声明功能介绍
pair();
构造空pair
template<class U, class V> pair (const pair<U,V>& pr);
拷贝构造
pair (const first_type& a, const second_type& b);
分别用两个值初始化pair,即分别初始化pair中的first和second元素
pair& operator= (const pair& pr);
通过对象进行赋值

例子: 

#include <iostream>
using namespace std;int main()
{pair<int, int> p(1, 2);//初始化paircout << p.first << " " << p.second << endl;pair<int, int> pp(p);//拷贝构造pp.first = 3;pp.second = 4;cout << pp.first << " " << pp.second << endl;pair<int, int> ret = pp;//赋值ret.first = 5;ret.second = 6;cout << ret.first << " " << ret.second << endl;return 0;
}

输出结果: 

 

1.3.2make_pair的介绍 

make_pair其实就是一个pair对象。其实现如下 

根据其实现,pair<T1,T2>(x,y) 构造了一个默认pair对象并返回,也就是说,make_pair(T1 x, T2 y) == pair<T1,T2>(x,y) 。所以make_pair即一个pair对象,采用make_pair的好处就是简短了一点。

例如:

#include <iostream>
using namespace std;int main()
{pair<int, int> p(make_pair<int,int>(1,2));//make_pair即一个pair对象,将该对象拷贝给pcout << p.first << " " << p.second << endl;return 0;
}

 输出结果:

go on~ 

二、set的介绍和使用

2.1set介绍

1.set是按照一定次序存储元素的容器,C++中是按中序遍历的。

2.在set中,元素key与value是一一对应的,且是唯一的。set中的key不能在容器中修改(元素总是const),但是可以插入和删除。因为修改元素,就破坏了树的结构。

3.在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。元素的相对顺序是严格确定的。

4.set容器通过key访问单个元素的速度通常比unordered_set(哈希实现)容器慢,但他们允许根据顺序对子集直接迭代。

5.set在底层是用红黑树实现的。

注意:

1.与map/multimap不同,map/multimap中存储的是真正的键值对<key,value>,set中只放value,但在底层实际存放的是由<value,value>构成的键值对。

2.set实际使用不需要构造键值对,只需传value参数即可。

3.set中的元素不可以重复,所以在插入相同的元素时,set会进行去重

4.使用set的迭代器遍历元素,得到的是有序序列,因为set底层是以中序的方式遍历

5.set中的元素默认按照小于来比较

6.set中查找某个元素,时间复杂度为:log N

7.红黑树依然是搜索二叉树,只不过其实现二叉搜索树的方式不同,优化了最初的二叉搜索树的缺点。 

set的第一个参数,存放元素的类型,第二个参数表示set元素默认按照小于来比较,第三个参数表示元素空间的管理方式,这个先不做了解,不影响我们的使用模拟实现。

2.2set使用

 2.2.1构造 

函数声明功能介绍
explicit set (const key_compare&comp=key_compare(),const allocator_type& alloc = allocator_type());
构造空set
template <class InputIterator>set (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
用[first,last)区间中的元素构造set
set (const set& x);
拷贝构造

例子: 

#include <iostream>
#include <set>
using namespace std;int main()
{int arr[] = { 2,34,6,6,56,8,321,9,4,88 };set<int> s(arr, arr + sizeof(arr)/sizeof(arr[0]));//迭代器区间构造for (auto e : s){cout << e << " ";}cout << endl;set<int> s1(s);//拷贝构造for (auto e : s1){cout << e << " ";}cout << endl;return 0;
}

输出结果: 

 

2.2.2容量

函数声明功能介绍
bool empty() const;
检测set是否为空,空返回true,否则返回false
size_type size() const;
返回set中有效元素的个数
size_type max_size() const;
返回set能够存储的最大容量

例子: 

#include <iostream>
#include <set>
using namespace std;int main()
{int arr[] = { 2,34,6,6,56,8,321,9,4,88 };set<int> s(arr, arr + sizeof(arr) / sizeof(arr[0]));//迭代器区间构造for (auto e : s){cout << e << " ";}cout << endl;cout << boolalpha << s.empty() << endl;//bool值形式打印cout << s.size() << endl;cout << s.max_size() << endl;return 0;
}

输出结果: 

 

2.2.3修改

函数声明功能介绍
pair<iterator,bool> insert(const value_type& x)在set中插入元素x,实际插入的是<x,x>构成的键值对,如果插入成功,返回<该元素在set中的位置,true>,失败,说明x在set中已经存在,返回<x在set中的位置,false>
void erase(iterator position)删除迭代器所指向position位置上的元素
size_type erase(const key_type& x)删除set中值为x的元素,返回删除的元素的个数
void erase(iterator first,iterator last)删除迭代器区间[first,last)中的元素
void swap(set& st)交换两个set中的元素
void clear()将set中的元素清空
iterator find(const key_type& x) const返回set中值为x的元素的位置,未找到,返回end()
size_type count(const key_type& x) const返回set中值为x的元素个数,因为set会去重,所以要么返回1,要么返回0

 其中key_type 代表第一个模板参数类型,即T

例子: 

#include <iostream>
#include <set>
using namespace std;int main()
{int arr[] = { 2,34,6,6,8,9,4};set<int> s(arr, arr + sizeof(arr) / sizeof(arr[0]));//迭代器区间构造set<int>::iterator it = s.begin();while(it != s.end()){cout << *it << " ";it++;}cout << endl;it= s.find(6);//返回元素的当前位置cout << *it << endl;cout << s.count(6) << endl;size_t num = s.erase(6);cout << num << endl;s.erase(s.begin());//删除迭代器当前位置元素it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;s.erase(s.begin(), s.end());//删除迭代器区间中的元素return 0;
}

输出结果: 

三、map的介绍和使用 

 3.1map介绍

 

1.map是关联式容器,存储由键值key和value组合的元素。key和value的组合元素跟set一样依然是按照key来进行比较排序。

2.在map中,key和value是一一对应的,即使类型不同。由于他们绑定在一起,并为他们取名为pair<key,value>,所以对于map而言Key和value元素存放在pair<const key, T>类模板当中。其typedef pair<const key, T> value_type;

3.map中通过键值访问单个元素的速度通常比unordered_map(哈希实现,遍历顺序是无序的)容器慢,但map遍历顺序是有序的。

4.map支持下标访问,通过key访问,即在[]中放入key,就可以找到key对应的value。

5.map由红黑树实现。

第一个参数表示key的类型,第二个参数表示value的类型。第三个参数表示map中的元素默认是按key来比较,且按小于来比。第四个参数表示空间配置器。

 3.2map使用

 3.2.1构造

函数声明功能介绍
explicit map (const key_compare&comp=key_compare(),const allocator_type& alloc = allocator_type());
构造空map
template <class InputIterator>map (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
用[first,last)区间中的元素构造map
map (const map& x);
拷贝构造
map& operator= (const map& x);
map& operator= (initializer_list<value_type> il);

通过对象进行初始化。

通过初始化列表进行初始化,C++11的用法

例子: 

#include <iostream>
#include <map>
using namespace std;int main()
{map<string, string> mp = { {"apple","苹果"}, {"banana","香蕉"}, {"orange","橙子"} };//初始化列表进行初始化,每个元素都是pair类型for (auto& e : mp)//访问map元素,实则就是pair中的元素{cout << e.first << ":" << e.second << endl;}cout << endl;map<string, string> mmp(mp.begin(), mp.end());//迭代器区间构造map<string, string>::iterator it = mmp.begin();while (it != mmp.end()){cout << it->first << ":" << it->second << endl;it++;}cout << endl;map<string, string> pm(mmp);//拷贝构造for (auto& e : pm){cout << e.first << ":" << e.second << endl;}return 0;
}

 输出结果:

3.2.2容量

函数声明功能简介
bool empty() const;
检测map中元素是否为空,是,返回true,否,返回false
size_type size() const;
返回map中有效元素的个数
mapped_type& operator[] (const key_type& k);

返回key对应的value。(支持插入,修改。若key不存在,则插入value,并返回。若存在,修改value,并返回)

mapped_type& at (const key_type& k);const mapped_type& at (const key_type& k) const;
返回key对应的value。(支持修改,不支持插入。若key不存在,抛异常。若存在,修改value,并返回)

 其中,mapped_type类型是第二个模板参数的类型,即T。

例子: 

#include <iostream>
#include <map>
using namespace std;int main()
{map<string, int> mp = { {"one",1},{"two",2},{"three",3},{"four",4} };cout << boolalpha << mp.empty() << endl;cout << mp.size() << endl;cout << "mp[one]:" << mp["one"] << endl;//返回对应的valuecout << "mp[two]:" << mp["two"] << endl;cout << "mp[three]:" << mp["three"] << endl;cout << "mp[four]:" << mp["four"] << endl << endl;mp["one"] = 5;//修改valuemp["two"] = 6;mp["three"] = 7;mp["four"] = 8;mp["nine"] = 9;//mp对象中没有<nine,9>。则表示新建key,插入9mp["ten"] = 10;cout << "mp[one]:" << mp["one"] << endl;//返回对应的valuecout << "mp[two]:" << mp["two"] << endl;cout << "mp[three]:" << mp["three"] << endl;cout << "mp[four]:" << mp["four"] << endl;cout << "mp[nine]:" << mp["nine"] << endl;cout << "mp[ten]:" << mp["ten"] << endl;return 0;
}

输出结果: 

 

3.2.3修改

函数声明功能介绍
pair<iterator,bool> insert(const value_type& x)在map中插入键值对x,注意x是一个键值对,即pair类型,返回值也是键值对:iterator代表新插入元素的位置,bool代表插入成功

void erase(iterator position)

size_type erase(const key_type& x)

void erase(iterator first,iterator last)

删除position位置上的元素

删除键值为x的元素

删除[first,last)区间中的元素

void swap(map<Key,T,Compare,Allocator>& mp)交换两个map中的元素
void clear()将map中的元素清空

iterator find(const key_type& x)

const_iterator find(const key_type& x) const

在map中插入key为x的元素,找到返回该元素的位置的迭代器,否则返回end()

在map中插入key为x的元素,找到返回该元素的位置的const迭代器,否则返回end()

size_type count(const key_type& x)返回key为x的键值在map中的个数,注意map汇总key是唯一的,因此该函数的返回值要么为0,要么为1,因此也可以用该函数来检测一个key是否在map中

对于operator[]重载实现,实则是按如下:

 

由于该长代码不好理解,将上述进行拆写,那么该重载的实现,可以按以下方式:

	mapped_type& operator[](const k& key){//插入成功,iterator指向的就是插入成功的位置,该位置类型为pair类型。插入失败,说明已经存在,iterator指向的就是已经存在的位置。pair<iterator, bool> p = this->insert(make_pair(k,mapped()));//p.first就是迭代器对象,指向<k,value>所在位置,p.first->second就是valuereturn p.first->second;}

接下来,就对修改的操作进行演示:

#include <iostream>
#include <map>
using namespace std;int main()
{map<string, string> mp;mp.insert(pair<string, string>("insert", "插入"));//将<"insert","插入">插入map中,用pair构造键值对//mp.insert(make_pair("insert","插入"));//通过make_pair构造键值对mp.insert(make_pair("fruit", "水果"));pair<map<string,string>::iterator, bool> p = mp.insert(make_pair("fruit", "水果"));//已经存在<"fruit","水果">,返回falsecout << boolalpha << p.second << endl;//通过operator[]向map中插入元素mp["apple"] = "苹果";//mp.at("peach") = "桃子";//"peach"不存在会抛异常,不会插入map<string, string> m;m.swap(mp);cout << boolalpha << mp.empty() << endl;m.erase("apple");map<string, string>::iterator it = m.find("apple");if (it != m.end()){cout << "苹果存在" << endl;}else{cout << "苹果不存在" << endl;}cout << m.count("peach") << endl;return 0;
}

 输出结果:

 总结一下map:

1.map中的元素是键值对,由pair管理。

2.map中的key是唯一的。

3.默认按照小于的方式对key进行比较

4.map中的元素是按中序的方式打印的,即有序的。

5.[]操作符,可插入,可修改。

四、multiset和multimap简单介绍使用

multiset和multimap跟set和map的使用一样。唯一功能不一样的是,multiset和multimap中的key不去重,正因为有了不去重的功能,所以对于他们就没必要提供operator[],因为该接口是先判断是否已经存在key,是,则返回key对应的value,可以进行对value修改,而不是继续插入key,否,则是新插入key,这就达到了去重的概念。所以他们不提供该接口,而对于其他接口的用法和set、map是类似的。

multiset: 

#include <iostream>
#include <set>
using namespace std;int main()
{string arr[] = { "apple","apple","banana","apple","orange","grape","peach" };multiset<string> s(arr, arr + sizeof(arr)/sizeof(arr[0]));//不去重for (auto& e : s){cout << e << endl;}return 0;
}

输出结果: 

 

multimap:

#include <iostream>
#include <map>
using namespace std;int main()
{multimap<string, string> mlp = { {"apple","苹果"},{"apple","苹果"},{"orange","橙子"},{"peach","桃子"},{"grape","葡萄"},{"apple","苹果"},{"banana","香蕉"} };for (auto& e : mlp){cout << e.first << ":" << e.second << endl;}mlp.insert(make_pair("peach","桃子"));mlp.erase("apple");//删除所有applemultimap<string, string>::iterator it = mlp.find("apple");if (it != mlp.end()){cout << "apple is also exist" << endl;}else{cout << "apple is not exist" << endl;}return 0;
}

 输出结果:

对于他们的底层实现会在之后的章节进一步实现,最后封装map和set 

end~ 

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

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

相关文章

MyBatis-Plus 2万字面试题详解

目录 什么是MyBatis-Plus? MyBatis-Plus与MyBatis有什么区别? MyBatis-Plus的主要优点有哪些?

ubuntu下pycharm闪退

pycharm依赖于jdk环境&#xff0c;要把java的jdk环境配置好&#xff0c;可参考以下链接&#xff1a; ubuntu2024.04下配置jdk&#xff08;安装java环境&#xff09;

力扣刷题总结--链表部分

链表部分 通用操作 链表的两种操作方式 不用虚拟头结点用虚拟头节点 为什么要定义cur指针 因为操作完链表以后&#xff0c;是要返回头节点的。如果你上来就操作头节点&#xff0c;那么头节点的值都改了&#xff0c;返回head就不是我们最开始的链表了。 写while循环的时候&am…

相机模型的内参、外参

相机模型的内参、外参 文章目录 相机模型的内参、外参1. 针孔模型、畸变模型&#xff08;内参&#xff09;2. 手眼标定&#xff08;外参&#xff09; Reference 这篇笔记主要参考&#xff1a;slam十四讲第二版&#xff08;高翔&#xff09; 相机将三维世界中的坐标点&#xff…

JVM线程和内存溢出问题排查思路

一、工具 Arthas&#xff1a;Arthas 是一款能在线查看应用 load、内存、gc、线程 等状态信息&#xff0c;并对业务问题进行诊断的工具&#xff0c;支持 JDK 6 和 Linux/Mac/Windows 系统。 jstack&#xff1a;jstack是JVM自带的Java堆栈跟踪工具&#xff0c;它用于打印出给定…

PDK安装及简介

目录 PDK简介 pdk安装 Standard Cell Library简介 IO Library简介 PDK简介 PDK&#xff1a;全称Process Design Kit&#xff0c;是工艺设计工具包的缩写&#xff0c;是制造和设计之间的沟通桥梁&#xff0c;是模拟电路设计的起始点。 具体来说&#xff0c;PDK是代工厂(FAB…

使用Docker进行Jmeter分布式搭建

大家好&#xff0c;随着技术的不断发展&#xff0c;对性能测试的要求也日益提高。在这样的背景下&#xff0c;如何利用 Docker 来巧妙地搭建 Jmeter 分布式成为了关键所在。现在&#xff0c;就让我们开启这场探索之旅&#xff0c;揭开其神秘的面纱。前段时间给大家分享了关于 L…

通信指挥类装备(多链路聚合设备)-应急通信指挥解决方案

现场通信指挥系统是一种功能全面的便携式音视频融合指挥通信平台&#xff0c;可实现现场应急救援指挥、多种通信手段融合、现场通信组网等功能&#xff0c;是现场指挥系统的延伸。 多链路聚合设备&#xff0c;是一款通信指挥类装备&#xff0c;具有 4G/5G&#xff0c;专网&…

Golang开发:切片的两种创建方式及区别

在Go语言中&#xff0c;var和make都可以用来初始化切片&#xff08;slice&#xff09;&#xff0c;但它们之间有一些重要的区别。 初始化方式&#xff1a; 使用var关键字声明的切片会被初始化为nil&#xff0c;即没有底层数组&#xff0c;长度为0&#xff0c;容量为0。使用make…

Free RTOS中Semaphore(二值信号量)的使用介绍

目录 概述 1 使用STM32Cube 配置信号量 1.1 引子 1.2 STM32Cube中配置FreeRTOS 1.3 STM32Cube生成Project 2 cmsis_os中信号量接口函数 2.1 函数&#xff1a;osSemaphoreNew 2.2 函数&#xff1a;osSemaphoreGetName 2.3 函数&#xff1a;osSemaphoreAcquire 2.4 函数…

hashmap数据结构为什么是链表

HashMap 数据结构中&#xff0c;链表通常用于解决哈希冲突。当不同的键映射到相同的哈希桶时&#xff0c;就会发生哈希冲突。链表是一种简单而有效的解决方法。 在 JDK 8 之前的 HashMap 实现中&#xff0c;当发生哈希冲突时&#xff0c;冲突的元素会被存储在同一个哈希桶中&a…

设计模式:外观模式(Facade)

设计模式&#xff1a;外观模式&#xff08;Facade&#xff09; 设计模式&#xff1a;外观模式&#xff08;Facade&#xff09;模式动机模式定义模式结构时序图模式实现在单线程环境下的测试在多线程环境下的测试模式分析优缺点适用场景应用场景模式扩展参考 设计模式&#xff1…

C++STL(queue和list)

3.6 queue 容器 3.6.1 queue 基本概念 概念&#xff1a;Queue是一种先进先出(First In First Out,FIFO)的数据结构&#xff0c;它有两个出口 队列容器允许从一端新增元素&#xff0c;从另一端移除元素队列中只有队头和队尾才可以被外界使用&#xff0c;因此队列不允许有遍历…

【Open AI】GPT-4o深夜发布:视觉、听觉跨越式升级

北京时间5月14日1点整&#xff0c;OpenAI 召开了首场春季发布会&#xff0c;CTO Mira Murati 在台上和团队用短短不到30分钟的时间&#xff0c;揭开了最新旗舰模型 GPT-4o 的神秘面纱&#xff0c;以及基于 GPT-4o 的 ChatGPT&#xff0c;均为免费使用。 本文内容来自OpenAI网站…

大数据面试 --- 六

1、Flink中的三种时间&#xff0c;哪一个性能会比较好 在Flink中主要分成三种时间&#xff1a; 事件时间&#xff08;Event Time&#xff09;注入时间&#xff08;Process Time&#xff09;、摄入时间&#xff08;Ingestion Time&#xff09; 事件时间指的是事件产生的时间…

课时126:awk实践_进阶知识_内置函数1

1.2.5 内置函数1 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习。 基础知识 简介 在awk内部预制了一些函数&#xff0c;借助于这些函数&#xff0c;我们可以实现相关场景的快速操作。这些内置函数的常见类型有&#xff1a;数值类内置函数int…

人工智能|深度学习——YOLOV8结构图

YoloV8相对于YoloV5的改进点&#xff1a; Replace the C3 module with the C2f module.Replace the first 6x6 Conv with 3x3 Conv in the Backbone.Delete two Convs (No.10 and No.14 in the YOLOv5 config).Replace the first 1x1 Conv with 3x3 Conv in the Bottleneck.Use…

【图神经网络——消息传递】

消息传递机制 画图先&#xff1a;导包&#xff1a;画图&#xff1a; 实现消息传递&#xff1a;例子一&#xff1a;例子二&#xff1a; 画图先&#xff1a; 导包&#xff1a; import networkx as nx import matplotlib.pyplot as plt import torch from torch_geometric.nn im…

Linux操作系统最著名的两大系列Red Hat和Debian

Linux操作系统可以根据其背后的项目或社区分为不同的系列&#xff0c;其中最著名的两大系列是Red Hat系列和Debian系列。 1.著名的两大系列是Red Hat和Debian Red Hat系列&#xff1a; Red Hat Enterprise Linux (RHEL)&#xff1a;这是Red Hat公司推出的企业级操作系统&#…

【LAMMPS学习】十、LAMMPS辅助工具(1)

10. 辅助工具 LAMMPS 被设计为用于执行分子动力学计算的计算内核。设置和分析模拟通常需要额外的预处理和后处理步骤。此类工具的列表可以在 LAMMPS 网页上的以下链接中找到&#xff1a; 前/后处理 外部 LAMMPS 软件包和工具 Pizza.py 工具包 Pizza.py 的最后一个链接是桑迪…