快捷搜索:  汽车  科技

map的原理(一文读懂map和multimap的差异原理)

map的原理(一文读懂map和multimap的差异原理)map的测试代码输出日志map的红黑树效果图(0 "zero")、(1 "one")、(5 "five")、(3 "three1")、(4 "four1")、(3 "three2")、(4 "four2")、(3 "three3")、(4 "four3")2.查看map和multimap最终插入和查询效果:①map的红黑树效果图和测试代码输出日志

概述

map和multimap的共同点:

  • map/multimap都是存储键值对的结构,可以改变value但是禁止改变key。
  • map/multimap都是基于红黑树,故都是有序的,排序的依据是key,默认排序规则都是升序。
  • map/multimap提供遍历操作及迭代器,按照正常规则( iter)遍历,便能获得排序状态。
  • map和multimap都定义于头文件 <map> 中。

map和multimap的差异点:

  • map的key是不能重复的,可以使用at()或[]操作符进行查找或修改数据;
  • multimap的key是可以重复的,未提供 at() 成员方法,也没有重载 [] 运算符;
通过代码分析原理

我们先写两个测试函数(为了提高大家的阅读体验,测试代码放在文章最后进行展示),看一下map和multimap在插入和查找方面的不同的点和相同点。

1.map和multimap先依次插入如下同样数据:

(0 "zero")、(1 "one")、(5 "five")、(3 "three1")、(4 "four1")、(3 "three2")、(4 "four2")、(3 "three3")、(4 "four3")

2.查看map和multimap最终插入和查询效果:

map的红黑树效果图和测试代码输出日志

map的原理(一文读懂map和multimap的差异原理)(1)

map的红黑树效果图

map的原理(一文读懂map和multimap的差异原理)(2)

map的测试代码输出日志

multimap的红黑树效果图和测试代码输出日志

map的原理(一文读懂map和multimap的差异原理)(3)

multimap的红黑树效果图和测试代码输出日志

3.分析map和multimap的差异原理:

map插入操作使用的是rb tree的insert_unique()函数,key不可重复,insert的返回值类型是pair<iterator bool>,第二个参数bool表示插入是否成功。

map的原理(一文读懂map和multimap的差异原理)(4)

<STL源码剖析>片段

map的原理(一文读懂map和multimap的差异原理)(5)

<STL源码剖析>片段

multimap插入操作使用的是rb tree的insert_equal()函数,key可以重复,insert的返回值类型是iterator。

map的原理(一文读懂map和multimap的差异原理)(6)

<STL源码剖析>片段

③map和multimap元素的查找原理是一样的。

multimap的查找方法主要有如下几种(map虽然常用find函数,但也支持其他几种查找方法):

find(key)

在 multimap 容器中查找首个键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。

lower_bound(key)

返回一个指向当前 multimap 容器中第一个大于或等于 key 的键值对的双向迭代器。

upper_bound(key)

返回一个指向当前 multimap 容器中第一个大于 key 的键值对的迭代器。

equal_range(key)

该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。

find的查找原理

map的原理(一文读懂map和multimap的差异原理)(7)

<STL源码剖析>片段

equal_range/(lower_bound upper_bound)的查找原理:

大家可以结合上述表格内容和“②multimap的红黑树效果图”内容对比查看,此处就不再文字描述了。

示例代码

#include<iostream>

#include<map>

using namespace std;

void fun_multimap_test()

{

//构造数据

multimap<int string> m_map = { {0 "zero"} {1 "one"} };

m_map.insert(pair<int string>(5 "five"));

m_map.insert(make_pair(3 "three1"));

m_map.insert(pair<int string>(4 "four1"));

m_map.insert(make_pair(3 "three2"));

m_map.insert(pair<int string>(4 "four2"));

m_map.insert(make_pair(3 "three3"));

m_map.insert(pair<int string>(4 "four3"));

//打印数据

cout << endl;

cout << " multimap 最大允许存储数据个数:" << m_map.max_size() << endl;

cout << " 实际元素个数:" << m_map.size() << " 打印排序后的数据:" << endl;

multimap<int string>::iterator iter_print = m_map.begin();

for (; iter_print != m_map.end(); iter_print)

{

cout << " 迭代器地址:" << &*iter_print << " 键:" << (*iter_print).first << " 值:" << (*iter_print).second << endl;

}

//查找数据

size_t m_count = m_map.count(3);

cout << endl << " key=3的元素个数:" << m_count << endl;

//使用equal_range()获取指向键值匹配元素下界和上界的迭代器

cout << endl;

pair<multimap<int string>::iterator multimap<int string>::iterator> result = m_map.equal_range(3);

cout << " equal_range first 迭代器地址:" << &*(result.first) << endl;

cout << " equal_range second 迭代器地址:" << &*(result.second) << endl;

for (multimap<int string >::iterator it = result.first; it != result.second; it)

{

cout << " 查到数据的迭代器地址:" << &*it << " 键:" << it->first << " 值:" << it->second << endl;

}

//小测试

cout << endl << " 打印equal_range(3)返回迭代器再前和再后一个元素的信息:" << endl;

auto iter_1 = --(result.first);

cout << " equal_range --first 迭代器地址:" << &*iter_1 << " 键:" << iter_1->first << " 值:" << iter_1->second << endl;

auto iter_2 = (result.second);

cout << " equal_range second 迭代器地址:" << &*iter_2 << " 键:" << iter_2->first << " 值:" << iter_2->second << endl;

//使用lower_bound()和upper_bound()获取指向键值匹配元素下界和上界的迭代器

cout << endl;

auto iter_lower = m_map.lower_bound(3);

auto iter_upper = m_map.upper_bound(3);

cout << " lower_bound 迭代器地址:" << &*(iter_lower) << " 键:" << iter_lower->first << " 值:" << iter_lower->second << endl;

cout << " upper_bound 迭代器地址:" << &*(iter_upper) << " 键:" << iter_upper->first << " 值:" << iter_upper->second << endl;

for (multimap<int string >::iterator it = iter_lower; it != iter_upper; it)

{

cout << " 查到数据的迭代器地址:" << &*it << " 键:" << it->first << " 值:" << it->second << endl;

}

//使用find()和count()获取指向键值匹配的迭代器

cout << endl << " 打印find(3)结合count()信息:" << endl;

auto itr = m_map.find(3);

for (size_t i = 0; i < m_count; i itr)

{

cout << " 查到数据的迭代器地址:" << &*itr << " 键:" << itr->first << " 值:" << itr->second << endl;

}

}

void fun_map_test()

{

//构造数据

map<int string> normal_map = { {0 "zero"} {1 "one"} };

normal_map[5] = "five";

normal_map.insert(make_pair(3 "three1"));

normal_map.insert(pair<int string>(4 "four1"));

normal_map.insert(make_pair(3 "three2"));

normal_map.insert(pair<int string>(4 "four2"));

normal_map.insert(make_pair(3 "three3"));

normal_map.insert(pair<int string>(4 "four3"));

//打印数据

cout << endl;

cout << " map 最大允许存储数据个数:" << normal_map.max_size() << endl;

cout << " 实际元素个数:" << normal_map.size() << " 打印排序后的数据:" << endl;

map<int string>::iterator iter_print = normal_map.begin();

for (; iter_print != normal_map.end(); iter_print)

{

cout << " 迭代器地址:" << &*iter_print << " 键:" << (*iter_print).first << " 值:" << (*iter_print).second << endl;

}

//查找数据

size_t m_count = normal_map.count(3);

cout << endl << " key=3的元素个数:" << m_count << endl;

//使用equal_range()获取指向键值匹配元素下界和上界的迭代器

cout << endl;

pair<map<int string>::iterator map<int string>::iterator> result = normal_map.equal_range(3);

cout << " equal_range first 迭代器地址:" << &*(result.first) << endl;

cout << " equal_range second 迭代器地址:" << &*(result.second) << endl;

for (map<int string >::iterator it = result.first; it != result.second; it)

{

cout << " 查到数据的迭代器地址:" << &*it << " 键:" << it->first << " 值:" << it->second << endl;

}

//小测试

cout << endl << " 打印equal_range(3)返回迭代器再前和再后一个元素的信息:" << endl;

auto iter_1 = --(result.first);

cout << " equal_range --first 迭代器地址:" << &*iter_1 << " 键:" << iter_1->first << " 值:" << iter_1->second << endl;

auto iter_2 = (result.second);

cout << " equal_range second 迭代器地址:" << &*iter_2 << " 键:" << iter_2->first << " 值:" << iter_2->second << endl;

//使用lower_bound()和upper_bound()获取指向键值匹配元素下界和上界的迭代器

cout << endl;

auto iter_lower = normal_map.lower_bound(3);

auto iter_upper = normal_map.upper_bound(3);

cout << " lower_bound 迭代器地址:" << &*(iter_lower) << " 键:" << iter_lower->first << " 值:" << iter_lower->second << endl;

cout << " upper_bound 迭代器地址:" << &*(iter_upper) << " 键:" << iter_upper->first << " 值:" << iter_upper->second << endl;

for (map<int string >::iterator it = iter_lower; it != iter_upper; it)

{

cout << " 查到数据的迭代器地址:" << &*it << " 键:" << it->first << " 值:" << it->second << endl;

}

//使用find()和count()获取指向键值匹配的迭代器

cout << endl << " 打印find(3)结合count()信息:" << endl;

auto itr = normal_map.find(3);

for (size_t i = 0; i < m_count; i itr)

{

cout << " 查到数据的迭代器地址:" << &*itr << " 键:" << itr->first << " 值:" << itr->second << endl;

}

}

int main()

{

fun_multimap_test();

fun_map_test();

return 0;

}


原创不易,欢迎点赞、收藏、关注!

猜您喜欢: