【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

相关文章

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

Go语言利用泛型封装常见的Map操作

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感... 目录什么是泛型泛型解决了什么问题Go泛型基于泛型的常见Map操作代码合集总结什么是泛型泛型是一种编程范式,允

MYSQL关联关系查询方式

《MYSQL关联关系查询方式》文章详细介绍了MySQL中如何使用内连接和左外连接进行表的关联查询,并展示了如何选择列和使用别名,文章还提供了一些关于查询优化的建议,并鼓励读者参考和支持脚本之家... 目录mysql关联关系查询关联关系查询这个查询做了以下几件事MySQL自关联查询总结MYSQL关联关系查询

JSON字符串转成java的Map对象详细步骤

《JSON字符串转成java的Map对象详细步骤》:本文主要介绍如何将JSON字符串转换为Java对象的步骤,包括定义Element类、使用Jackson库解析JSON和添加依赖,文中通过代码介绍... 目录步骤 1: 定义 Element 类步骤 2: 使用 Jackson 库解析 jsON步骤 3: 添

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Spring核心思想之浅谈IoC容器与依赖倒置(DI)

《Spring核心思想之浅谈IoC容器与依赖倒置(DI)》文章介绍了Spring的IoC和DI机制,以及MyBatis的动态代理,通过注解和反射,Spring能够自动管理对象的创建和依赖注入,而MyB... 目录一、控制反转 IoC二、依赖倒置 DI1. 详细概念2. Spring 中 DI 的实现原理三、

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听