【STL源码剖析】第五章 关联式容器 之 set、map、multiset和multimap

2024-08-22 13:08

本文主要是介绍【STL源码剖析】第五章 关联式容器 之 set、map、multiset和multimap,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

set

  1. 所有的元素都会根据元素的键值自动被排序。set的元素不像map那样可以同时拥有实值(value)和键值(key),set元素的键值就是实值。set不允许两个元素有相同的键值。

  2. 不可以通过set的迭代器改变set的元素值。因为set元素值就是其键值,关系到set元素的排列规则。如果任意改变set元素值,会严重破坏set组织。set源码中,set<T>::iterator被定义为底层RB-tree的const_iterator,杜绝写入操作。换句话,set iterators是一种constant iterators。

  3. set拥有与list相同的某些性质:当客户端对它进行元素新增操作(insert)或删除操作(erase)时,操作之前的所有迭代器,在操作完成之后依然有效。当然,被删除的那个元素的迭代器必然是个例外。

  4. STL set以RB-tree为底层机制,set的操作几乎都是转调用RB-tree的函数而已。

set测试代码:

  #include<set>#include<iostream>using namespace std;int main(){    int ia[] = { 5, 3, 4, 1, 6, 2 };    set<int> iset(begin(ia), end(ia));    cout << "size=" << iset.size() << endl; //size=6    cout << "3 count=" << iset.count(3) << endl;//3 count=1    iset.insert(3);    cout << "size=" << iset.size() << endl;//size=6    cout << "3 count=" << iset.count(3) << endl;//3 count=1    iset.insert(7);    cout << "size=" << iset.size() << endl;//size=7    cout << "3 count=" << iset.count(3) << endl;//3 count=1    iset.erase(1);    cout << "size=" << iset.size() << endl;//size=6    cout << "1 count=" << iset.count(1) << endl;//1 count=0    set<int>::iterator it;    for (it = iset.begin(); it != iset.end(); ++it)        cout << *it << " "; //2 3 4 5 6 7    cout << endl;    it = find(iset.begin(), iset.end(), 3);    if (it != iset.end())        cout << "3 found" << endl;//3 found    it = find(iset.begin(), iset.end(), 1);    if (it == iset.end())        cout << "1 not found" << endl;//1 not found    system("pause");    return 0;}

map

  1. map的特性是,所有元素都会根据元素的键值自动被排序。map的所有元素都是pair,同时拥有实值(value)和键值(key)。pair的第一元素被视为键值,第二元素被视为实值。map不允许两个元素拥有相同的键值。下面是<stl_pair.h>中pair定义:

      template<class T1,class T2>struct pair{    typedef T1 first_type;    typedef T2 second_type;    T1 first;    T2 second;    pair():first(T1()),second(T2()) {}    pair(const T1& a,const T2& b):first(a),second(b) {}}

  2. 不能通过map的迭代器改变map的键值,但通过map的迭代器能改变map的实值。因此map的iterators既不是一种const iterators,也不是一种mutable iterators。

  3. map拥有和list相同的某些性质:当客户端对它进行元素新增操作(insert)或删除操作(erase)时,操作之前的所有迭代器,在操作完成之后都依然有效。当然,被删除的那个元素的迭代器必然是个例外。

  4. 由于RB-tree是一种平衡二叉搜索树,自动排序的效果很不错,所以标准的STL map即以RB-tree为底层机制。又由于map所开放的各种操作接口,RB-tree也都提供了,所以几乎所有的map操作行为,都只是转调用RB-tree的操作行为而已。

  #include<map>#include<iostream>#include<string>using namespace std;int main(){    map<string, int> simap;            //以string为键值,以int为实值    simap[string("jjhou")] = 1;        //第一对内容是("jjhou",1)    simap[string("jerry")] = 2;        //第一对内容是("jerry",2)    simap[string("jason")] = 3;        //第一对内容是("jason",3)    simap[string("jimmy")] = 4;        //第一对内容是("jimmy",4)    pair<string, int> value(string("david"), 5);    simap.insert(value);    map<string, int>::iterator simap_iter = simap.begin();    for (; simap_iter != simap.end(); ++simap_iter)        cout << simap_iter->first << ' ' << simap_iter->second << endl;                                                                //david 5   //按键值排序                                                                //jason 3                                                                //jerry 2                                                                //jimmy 4                                                                //jjhou 1    int number = simap[string("jjhou")];    cout << number << endl;                                     //1    map<string, int>::iterator ite1;    //面对关联式容器,应使用其所提供的find函数来搜寻元素,会比STL算法find()更有效率。因为STL find()只是循序搜索    ite1 = simap.find(string("mchen"));    if (ite1 == simap.end())        cout << "mchen not found" << endl;                      //mchen not found    ite1 = simap.find(string("jerry"));    if (ite1 != simap.end())        cout << "jerry found" << endl;                         //jerry found    ite1->second = 9;    int number2 = simap[string("jerry")];    cout << number2 << endl;                                   //9}

multiset

multiset的特性以及用法和set完全相同,唯一的差别在于它允许键值重复,因此它的插入操作采用的是底层机制RB-tree的insert_equal()而非insert_unique()。

  #include<set>#include<iostream>#include<vector>using namespace std;int main() {    vector<int> a = { 5, 3, 4, 1, 6, 2 };    multiset<int> iset(a.begin(),a.end());    cout << "size=" << iset.size() << endl; //size=6    cout << "3 count=" << iset.count(3) << endl;//3 count=1    iset.insert(3); //和set区别的地方    cout << "size=" << iset.size() << endl;//size=7    cout << "3 count=" << iset.count(3) << endl;//3 count=2    iset.insert(7);    cout << "size=" << iset.size() << endl;//size=8    cout << "3 count=" << iset.count(3) << endl;//3 count=2    iset.erase(1);    cout << "size=" << iset.size() << endl;//size=7    cout << "1 count=" << iset.count(1) << endl;//1 count=0    set<int>::iterator it;    for (it = iset.begin(); it != iset.end(); ++it)        cout << *it << " "; //2 3 3 4 5 6 7    cout << endl;    it = find(iset.begin(), iset.end(), 3);    if (it != iset.end())        cout << "3 found" << endl;//3 found    it = find(iset.begin(), iset.end(), 1);    if (it == iset.end())        cout << "1 not found" << endl;//1 not found    system("pause");    return 0;}

multimap

multimap的特性以及用法与map完全相同,唯一的差别在于它允许键值重复,因此它的插入操作采用的是底层机制RB-tree的insert_equal()而非insert_unique()。

  #include<map>#include<string>#include<iostream>using namespace std;int main(){    multimap<string, int> mp;//multimap没有下标操作    mp.insert(pair<string, int>("Jack", 1));    mp.insert(pair<string, int>("John", 2));    mp.insert(pair<string, int>("Lily", 3));    mp.insert(pair<string, int>("Kate", 4));//按键值字典序排序    mp.insert(pair<string, int>("Tom", 5));              //Jack 1    mp.insert(pair<string, int>("John", 8));            //John 2                                                           //John 8       map<string, int>::iterator it;                      //Kate 4    for (it = mp.begin(); it != mp.end(); ++it)         //Lily 3        cout << it->first << " " << it->second << endl; //Tom 5    it = mp.find("John");    if (it != mp.end())        cout << "John found" << endl; //John found    it->second = 8;    it = mp.find("John");    cout << it->second << endl;//8    system("pause");    return 0;}

这篇关于【STL源码剖析】第五章 关联式容器 之 set、map、multiset和multimap的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096361

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

python语言中的常用容器(集合)示例详解

《python语言中的常用容器(集合)示例详解》Python集合是一种无序且不重复的数据容器,它可以存储任意类型的对象,包括数字、字符串、元组等,下面:本文主要介绍python语言中常用容器(集合... 目录1.核心内置容器1. 列表2. 元组3. 集合4. 冻结集合5. 字典2.collections模块

Spring Boot中获取IOC容器的多种方式

《SpringBoot中获取IOC容器的多种方式》本文主要介绍了SpringBoot中获取IOC容器的多种方式,包括直接注入、实现ApplicationContextAware接口、通过Spring... 目录1. 直接注入ApplicationContext2. 实现ApplicationContextA

linux配置podman阿里云容器镜像加速器详解

《linux配置podman阿里云容器镜像加速器详解》本文指导如何配置Podman使用阿里云容器镜像加速器:登录阿里云获取专属加速地址,修改Podman配置文件并移除https://前缀,最后拉取镜像... 目录1.下载podman2.获取阿里云个人容器镜像加速器地址3.更改podman配置文件4.使用po

java 恺撒加密/解密实现原理(附带源码)

《java恺撒加密/解密实现原理(附带源码)》本文介绍Java实现恺撒加密与解密,通过固定位移量对字母进行循环替换,保留大小写及非字母字符,由于其实现简单、易于理解,恺撒加密常被用作学习加密算法的入... 目录Java 恺撒加密/解密实现1. 项目背景与介绍2. 相关知识2.1 恺撒加密算法原理2.2 Ja

Nginx屏蔽服务器名称与版本信息方式(源码级修改)

《Nginx屏蔽服务器名称与版本信息方式(源码级修改)》本文详解如何通过源码修改Nginx1.25.4,移除Server响应头中的服务类型和版本信息,以增强安全性,需重新配置、编译、安装,升级时需重复... 目录一、背景与目的二、适用版本三、操作步骤修改源码文件四、后续操作提示五、注意事项六、总结一、背景与

k8s容器放开锁内存限制问题

《k8s容器放开锁内存限制问题》nccl-test容器运行mpirun时因NCCL_BUFFSIZE过大导致OOM,需通过修改docker服务配置文件,将LimitMEMLOCK设为infinity并... 目录问题问题确认放开容器max locked memory限制总结参考:https://Access

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码