STL关联式容器:map 与 set 的使用

目录

一、序列式容器与关联式容器

[1.1 序列式容器](#1.1 序列式容器)

[1.2 关联式容器](#1.2 关联式容器)

[1.3 map 和 set 底层结构](#1.3 map 和 set 底层结构)

[二、set 的使用](#二、set 的使用)

[2.1 set 的特点](#2.1 set 的特点)

[2.2 set 常用操作](#2.2 set 常用操作)

(1)插入

(2)遍历

(3)查找

(4)删除

(5)计数

[(6) lower_bound和upper_bound](#(6) lower_bound和upper_bound)

[2.3 multiset](#2.3 multiset)

[三、map 的使用](#三、map 的使用)

[3.1 map 的特点](#3.1 map 的特点)

[3.2 map 基本结构](#3.2 map 基本结构)

[3.3 pair对象](#3.3 pair对象)

[3.4 插入/初始化](#3.4 插入/初始化)

[3.5 访问与修改](#3.5 访问与修改)

[(1)通过 find](#(1)通过 find)

[(2)通过 []](#(2)通过 [])

[3.6 删除](#3.6 删除)

[3.7 遍历](#3.7 遍历)

[3.8 multimap vs map](#3.8 multimap vs map)


一、序列式容器与关联式容器

1.1 序列式容器

STL 中常见的 string、vector、list、deque、array、forward_list 等属于序列式容器

特点:

逻辑结构是线性序列

元素之间关系不强

主要按"位置"访问

可以随意交换元素位置,不影响整体结构

本质:按顺序存储数据


1.2 关联式容器

关联式容器包括:

  • set / multiset

  • map / multimap

  • unordered_set / unordered_map

特点:

逻辑结构是非线性(通常是树结构)

元素之间存在"键值关系"

按 key 进行存储和查找

不能随意交换位置,否则结构被破坏

本质:按关键字组织数据


1.3 map 和 set 底层结构

底层实现:红黑树(平衡二叉搜索树)

时间复杂度:O(logN)

遍历方式:中序遍历(天然有序)


二、set 的使用

2.1 set 的特点

自动去重

自动排序(默认升序)

key 即 value

不允许修改元素值


2.2 set 常用操作

(1)插入

cpp 复制代码
set<int> s;
s.insert(10);
s.insert(20);

(2)遍历

cpp 复制代码
for (auto e : s)
{
    cout << e << " ";
}

(3)查找

cpp 复制代码
if (s.find(10) != s.end())
{
    cout << "存在";
}

返回10这个值的迭代器


(4)删除

cpp 复制代码
s.erase(10);        // 按值删除
s.erase(s.begin()); // 按迭代器删除

这里也存在迭代器失效的问题,所以用vs去访问的话会报错


(5)计数

cpp 复制代码
cout << s.count(10);

返回10的个数,一般适用于multiset

(6) lower_bound和upper_bound

cpp 复制代码
#include<set>
#include<iostream>
using namespace std;
int main()
{
	std::set<int> myset;
	for (int i = 1; i < 10; i++)
		myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90
	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;

	// [30, 50]值
	// [25, 55]值
	 
	//// 返回 >= 30
	auto itlow = myset.lower_bound(30);
	//// 返回 > 50
	auto itup = myset.upper_bound(50);

	// 返回 >= 25
	//auto itlow = myset.lower_bound(25);
	// 返回 > 55
	//auto itup = myset.upper_bound(55);

	// 删除这段区间的值
	myset.erase(itlow, itup);
	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;
}

这里删除传入的迭代器都是左闭右开,所以要删除一段区间,左迭代器可以用lower_bound得到,它可以返回>=某个值的迭代器,右迭代器可以传upper_bound,它返回>某个值的迭代器


2.3 multiset

特点:

允许重复元素

仍然有序

区别:

容器 是否去重
set 去重
multiset 不去重

三、map 的使用

3.1 map 的特点

key-value 结构

key 不可重复

自动按 key 排序

支持修改 value


3.2 map 基本结构

cpp 复制代码
map<Key, value>

例如:

复制代码
map<string, int> m;

3.3 pair对象

pair是一个类模板

里面有2个成员变量

一个是first,一个是second

pair常被用于map,作参数,作返回值

first相当于key,second相当于value,我们可以通过pair来对key/value进行操作

3.4 插入/初始化

cpp 复制代码
pair<string, string> kv1("first", "第一个");
map<string, string> dict = {kv1, pair<string, string>("second", "第二个")};
map<string, string> dict = { {"left", "左边"}, {"right", "右边"}, {"insert", "插入"},{ "string", "字符串" } };

这里value_type 就是pair,map的初始化支持传入一个pair对象,可以是有名对象,也可以是匿名对象,或者直接写成传一个initializer_list的对象,c++11支持多参数的隐式类型转换,里面的花括号生成一个pair对象,所有pair再转换成一个initializer_list的对象

cpp 复制代码
pair<string, string> kv1("first", "第一个");
dict.insert(kv1);

dict.insert(pair<string, string>("second", "第二个"));

dict.insert(make_pair("sort", "排序"));

// C++11
dict.insert({ "auto", "自动的" });

这里插入,可以传一个pair对象,可以传一个函数模板make_pair

他会返回一个pair对象,并且可以自动推导类型,日常使用也是非常常用的

cpp 复制代码
dict.insert({ "auto", "自动的" });

// 插入时只看key,value不相等不会更新
dict.insert({ "auto", "自动的xxxx" });

插入不会自动更新


3.5 访问与修改

(1)通过 find

复制代码
auto it = m.find("apple");
if (it != m.end())
{
    it->second++;
}

这里的second是一个pair对象的一个成员变量


(2)通过 []

复制代码
m["apple"] = 10;
m["banana"]++;

特点:

key 不存在 → 自动插入

key 存在 → 修改 value

它跟insert的功能是相似的,所以要确保key存在再用,不然就又会插入一个不存在的key,谨慎使用


3.6 删除

复制代码
m.erase("apple");
m.erase(it);

3.7 遍历

复制代码
for (auto& e : m)
{
    cout << e.first << ":" << e.second;
}

3.8 multimap vs map

容器 是否允许重复 key
map 不允许
multimap 允许

区别:

multimap 不能使用 []

find 可能返回多个 key 中第一个

相关推荐
charlie1145141911 小时前
现代C++特性指南(5)——RAII 深入理解:资源管理的基石
开发语言·c++·现代c++
神仙别闹2 小时前
基于QT(C++)+Sqlite3实现单词消除游戏系统
c++·qt·sqlite
yunn_2 小时前
基于C++ 11的线程池实现
c++
人间乄惊鸿客3 小时前
c++自记录
java·开发语言·c++
MC皮蛋侠客3 小时前
C++17 多线程系列(一):线程基础——std::thread 完全指南
开发语言·c++·多线程
MC皮蛋侠客3 小时前
Perf 火焰图深度实战:CPU 性能分析与异常排查完全指南
linux·c++·性能分析·perf·火焰图
熊孩纸的世界你不懂3 小时前
Qt + SQLite 配置与使用指南
c++·qt
码上有光3 小时前
c++模板进阶知识讲解(对模板的进一步的运用与理解)
java·前端·c++·特化·模板进阶·偏特化
Zhang~Ling4 小时前
C++ 继承机制详解下:多继承、虚继承与菱形继承底层原理
开发语言·c++·算法