map和set的应用

map、set

  • [1. 序列式和关联式容器](#1. 序列式和关联式容器)
  • 2.set和multiset
    • [2.1 构造](#2.1 构造)
    • [2.2 迭代器](#2.2 迭代器)
    • [2.3 修改](#2.3 修改)
  • [3. map和multimap](#3. map和multimap)
    • [3.1 map](#3.1 map)
    • [3.2. multimap](#3.2. multimap)

1. 序列式和关联式容器

序列式容器 :比如:vector、list、deque、forward_list等,这些容器统称为序列式容器,因为其底层为线性序列 的数据结构,里面存储的是元素本身
关联式容器:关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。底层是树形结构(红黑树)。

2.set和multiset

两者的区别在于set不允许数据冗余,即不能存储相同的数据。multiset可以存储相同的数据。

2.1 构造

cpp 复制代码
set<string> s1; //空初始化

int arr[10] = { 4,0,9,3,5,8,7,1,2,11 };
set<int> s(arr, arr + 10); //迭代器区间初始化

set<int> s2(s);  //拷贝构造

multiset同理。

2.2 迭代器

迭代器和其他容器类似。

cpp 复制代码
void testset()
{
	int arr[10] = { 4,0,9,3,5,8,7,1,2,11 };
	set<int> s(arr, arr + 10); 

	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	set<int>::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << " ";
		rit++;
	}
}

int main()
{
	testset();
	return 0;
}

运行结构如下

由于底层是搜索树,因此遍历结果为升序,反向遍历则为降序。

2.3 修改


count返回set内值为val的元素的个数,这个函数对于set没有太大作用。要么存在为1,要么不存在为0。因为set不允许数据冗余。对于multiset比较实用,可以统计某个元素的次数。


lower_bound返回第一个大于等于val的元素的迭代器。

upper_bound返回第一个大于val的元素的迭代器。

3. map和multimap

3.1 map

  1. map是关联式容器,它按照特定的次序(通过比较key的大小)存储由键值key和值value组合而成的元素。
  2. 在map中,键值key通常用于排序和唯一的标识元素,而值value中存储与此键值key关联的
    内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型
    value_type绑定在一起,为其取别名称为pair:
    typedef pair<const key, T> value_type;
  3. 在内部,map中的元素总是按照键值key进行比较排序的。
  4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序
    对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
  6. map通常被实现为红黑树。

map和multimap的接口和set类似。最不同的为map支持[ ]的访问。

cpp 复制代码
void test_map()
{
	map<string, string> dict;
	dict.insert(make_pair("1", "one")); //调用接口
	dict.insert({ "2", "two" });        //隐式类型转换
	dict.insert(pair<string,string>("0", "zero")); //匿名对象

	map<string, string>::iterator it = dict.begin();
	cout << it->first << ":" << it->second<<endl;

	map<string, int> fruit;
	fruit["苹果"];            //插入
	fruit["苹果"] = 8;     //修改
	fruit["香蕉"] = 3;     //插入+修改

	map<string, int>::iterator it1 = fruit.begin();
	while(it1!=fruit.end())
	{
			cout << it1->first << ":" << it1->second << endl;
			++it1;
	}

}

由于存储的是pair,所以使用->更方便访问结构内的成员

operator[] 的原理大致如下

map<string, int> fruit;

fruit["苹果"]; //插入

fruit["苹果"] = 8; //修改

fruit["香蕉"] = 3; //插入+修改

operator[] 具有以上的功能。

总结

  1. map中的的元素是键值对
  2. map中的key是唯一的,并且不能修改
  3. 默认按照小于的方式对key进行比较
  4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列
  5. map的底层为平衡搜索树(红黑树),查找效率比较高 O ( l o g 2 N ) O(log_2 N) O(log2N)
  6. 支持[]操作符,operator[]中实际进行插入查找。

3.2. multimap

  1. multimaps是关联式容器,它按照特定的顺序,存储由key和value组成的键值对<key,
    value>,其中多个键值对之间的key是可以重复的。
  2. 在multimap中,通常按照key排序和唯一的标识元素,而value存储与key关联的内
    容。key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起,
    value_type是组合key和value的键值对:
    typedef pair<const Key, T> value_type;
  3. multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代
    器直接遍历multimap中的元素可以得到关于key有序的序列。
  4. multimap在底层用红黑树来实现。
    注意:multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以
    重复的。

multimap的接口和map类似。但是没有重载operator[],因为key可以有很多个。

相关推荐
蜀黍@猿18 分钟前
【C++ 基础】从C到C++有哪些变化
c++
Am心若依旧40919 分钟前
[c++11(二)]Lambda表达式和Function包装器及bind函数
开发语言·c++
zh路西法29 分钟前
【C++决策和状态管理】从状态模式,有限状态机,行为树到决策树(一):从电梯出发的状态模式State Pattern
c++·决策树·状态模式
轩辰~43 分钟前
网络协议入门
linux·服务器·开发语言·网络·arm开发·c++·网络协议
lxyzcm1 小时前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
蜀黍@猿1 小时前
C/C++基础错题归纳
c++
雨中rain2 小时前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
ALISHENGYA3 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法
arong_xu3 小时前
现代C++锁介绍
c++·多线程·mutex
汤姆和杰瑞在瑞士吃糯米粑粑3 小时前
【C++学习篇】AVL树
开发语言·c++·学习