【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

相关文章

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

如何将Tomcat容器替换为Jetty容器

《如何将Tomcat容器替换为Jetty容器》:本文主要介绍如何将Tomcat容器替换为Jetty容器问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat容器替换为Jetty容器修改Maven依赖配置文件调整(可选)重新构建和运行总结Tomcat容器替

SpringBoot如何通过Map实现策略模式

《SpringBoot如何通过Map实现策略模式》策略模式是一种行为设计模式,它允许在运行时选择算法的行为,在Spring框架中,我们可以利用@Resource注解和Map集合来优雅地实现策略模式,这... 目录前言底层机制解析Spring的集合类型自动装配@Resource注解的行为实现原理使用直接使用M

Nginx指令add_header和proxy_set_header的区别及说明

《Nginx指令add_header和proxy_set_header的区别及说明》:本文主要介绍Nginx指令add_header和proxy_set_header的区别及说明,具有很好的参考价... 目录Nginx指令add_header和proxy_set_header区别如何理解反向代理?proxy

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

Python容器类型之列表/字典/元组/集合方式

《Python容器类型之列表/字典/元组/集合方式》:本文主要介绍Python容器类型之列表/字典/元组/集合方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 列表(List) - 有序可变序列1.1 基本特性1.2 核心操作1.3 应用场景2. 字典(D

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory