当前位置: 首页 > news >正文

34.二叉树进阶3(C++STL 关联式容器,set/map的介绍与使用)

⭐上篇文章:33.C++二叉树进阶2(二叉搜索树两种模型及其应用)-CSDN博客

⭐本篇代码:c++学习/19.map和set的使用用与模拟 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)

⭐标⭐是比较重要的部分

目录

一. 关联式容器与键值对

1.1 关联式容器

1.2 键值对

1.3 STL中常见的关联式容器 

二. STL set的使用 

2.1 set介绍

2.2 set构造接口⭐

2.3 迭代器接口

2.4 set容量接口

2.5 set修改接口⭐

2.6 set使用举例

三. STL map的使用 

3.1 构造键值对pair ⭐

3.2 map的遍历

3.3 map的operator[] ⭐

3.4 map的应用 

四. multiset和multimap 


一. 关联式容器与键值对

1.1 关联式容器

        STL中的 vector list stack queue priority_queue deque等容器都是序列式容器。它们的底层都是线性结构,且节点内除了指针就是自己本身的数据。

        而关联式容器除了指针以外,自己本身的值是一个<key,value>结构的键值对。这种容器的检索效率较高。

1.2 键值对

        键值对是一个结构<key,pair>。其中key代表键值,用于标识和访问对应的value。STL中键值对的定义如下(经过简化):

template<class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 seconde_type;

	pair(const first_type& a = T1(), const second_type& b = T2())
		:first(a), second(b)
	{}

	first_type first;
	seconde_type second;
};

1.3 STL中常见的关联式容器 

STL中常见的关联式容器有:

有序关联容器(底层为平衡二叉搜索树):map, set, multiset, multimap,                        

无序关联容器(底层为哈希):unordered_set, unordered_map 

二. STL set的使用 

2.1 set介绍

        set文档:set - C++ Reference (cplusplus.com)

set是二叉搜索树的key模型,可以用于搜索,排序,去重。且效率为O(log N)

set默认是按照小于来比较,所以排序是升序

2.2 set构造接口⭐

使用set需要包含头文件set

构造函数:

函数声明介绍
set (const Compare& comp = Compare(), const Allocator& = Allocator() );一般直接用于构造一个空的set
set (InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator() );使用迭代器[first,last)元素来构造一个set
set ( const set& x);拷贝构造

使用代码如下:

#include <iostream>
#include <set>    //使用set所需头文件
#include <vector>
using namespace std;


int main()
{
	vector<int> arr = { 1,2,3,4,5, };
	set<int> s1;
	set<int> s2(arr.begin(), arr.end());
	set<int> s3(s2);
	return 0;
}

2.3 迭代器接口

函数声明功能介绍
iterator begin()返回set中起始位置元素的迭代器
iterator end()返回set中最后一个元素后面的迭代器
const_iterator cbegin() const返回set中起始位置元素的const迭代器
const_iterator cend() const返回set中最后一个元素后面的const迭代
reverse_iterator rbegin()返回set第一个元素的反向迭代器,即end
reverse_iterator rend()返回set最后一个元素下一个位置的反向迭代器,即 rbegin
const_reverse_iterator crbegin() const返回set第一个元素的反向const迭代器,即cend
const_reverse_iterator crend() const返回set最后一个元素下一个位置的反向const迭代器, 即crbegin

2.4 set容量接口

函数接口功能介绍
bool empty() const判断容器是否为空
size_type size() const返回set容器中元素的个数
#include <iostream>
#include <set>
#include <vector>
using namespace std;


int main()
{
	vector<int> arr = { 1,2,3,4,5, };
	set<int> s1;
	set<int> s2(arr.begin(), arr.end());
	set<int> s3(s2);

	cout << s1.size() << endl;
	cout << s2.size() << endl;
	cout << s3.size() << endl;

	return 0;
}

 

2.5 set修改接口⭐

函数声明功能介绍
pair<iterator,bool>  insert ( const value_type& x )插入数据x,实际上是插入一个<x,x>的键值对,如果插入成功。返回 <元素x在set的位置,true>。如果set存在这个元素,则返回<元素x在set的位置,false>
void erase ( iterator position )删除set中position位置上的元素
size_type erase ( const key_type& x )删除set中值为x的元素,返回删除的元素的个数,没有返回0
void erase ( iterator first, iterator last )删除set中[first, last)区间中的元素
void swap ( set& st );v交换set中的元素
void clear ( )将set中的元素清
iterator find ( const key_type& x ) const返回set中值为x的元素的位置
size_type count ( const key_type& x ) const返回set中值为x的元素的个数

2.6 set使用举例

#include <iostream>
#include <set>
#include <vector>
using namespace std;

void test1()
{
	set<int> s;
	//set可以去重和排序
	s.insert(1);
	s.insert(8);
	s.insert(4);
	s.insert(15);
	s.insert(-5);
	s.insert(-5);
	s.insert(15);


	//迭代器遍历
	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;
	}
	cout << endl;

	//C++11 for循环
	for (const auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}


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

运行结果如下:

查找与删除

#include <iostream>
#include <set>
#include <algorithm>
using namespace std;

void printset(const set<int>& s)
{
	for (const auto& e : s)
		cout << e << " ";
	cout << endl;
}


void test1()
{
	set<int> s;
	//set可以去重和排序
	s.insert(1);
	s.insert(8);
	s.insert(4);
	s.insert(15);
	s.insert(-5);
	printset(s);

	int x;
	cout << "输入想要查找的数字:";
	cin >> x;

	//查找方式1,根据搜索二叉树性质查找,效率为O(logN)
	if (s.find(x) != s.end())
		cout << "找到了!" << endl;
	else
		cout << "没找到" << endl;

	//查找方式2
	if (s.count(x) != 0)
		cout << "找到了!" << endl;
	else
		cout << "没找到" << endl;

	//使用algorithm库中的find,这个查找是一个一个查找的,效率较低为O(N)
	if (find(s.begin(), s.end(), x) != s.end())
		cout << "找到了!" << endl;
	else
		cout << "没找到" << endl;

	//删除
	cout << "删除前" << endl;
	printset(s);
	s.erase(1);
	auto it = s.find(5);	//set中没有5,所以不会删除
	//注意,不可直接删除it,因为有可能这个数据不在容器中
	if (it != s.end())
		s.erase(it);
	cout << "删除1,5后" << endl;
	printset(s);

}



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

三. STL map的使用 

map的使用文档:map - C++ Reference (cplusplus.com)

map和set的接口非常相似,详细可以看这里的文档。这里只介绍map的特殊接口与使用

3.1 构造键值对pair ⭐

        map插入的数据都是键值对,所以我们需要构造键值对,常见的构造方法如下:

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;

void test()
{
	map<int, string> m;
	
	//1. 提高构造好键值对
	pair<int, string> p1(1, "A");	
	pair<int, string> p2(2, "B");
	m.insert(p1);
	m.insert(p2);

	//2. 通过匿名对象插入数据
	m.insert(pair<int, string>(3, "C"));
	m.insert(pair<int, string>(4, "D"));

	//3.使用make_pair构造键值对,这个比较常用
	m.insert(make_pair(5, "E"));
	m.insert(make_pair(6, "F"));
	m.insert(make_pair(7, "G"));
}


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

建议使用make_pair,简单方便 

3.2 map的遍历

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;


void printmap(const map<int, string> m)
{
	//1.迭代器遍历
	auto it = m.begin();
	while (it != m.end())
	{
		//使用箭头访问内部的数据
		cout << it->first << ":" << it->second << " " ;

		//使用解引用和.访问数据
		cout << (*it).first << ":" << (*it).second << " ";

		++it;
	}
	cout << endl;

	//2.C++11 基于范围的for循环
	for (const auto& kv : m)
	{
		cout << kv.first << ":" << kv.second << " " ;
	}
	cout << endl;

}

void test()
{
	map<int, string> m;
	
	//1. 提高构造好键值对
	pair<int, string> p1(1, "A");	
	pair<int, string> p2(2, "B");
	m.insert(p1);
	m.insert(p2);

	//2. 通过匿名对象插入数据
	m.insert(pair<int, string>(3, "C"));
	m.insert(pair<int, string>(4, "D"));

	//3.使用make_pair构造键值对,这个比较常用
	m.insert(make_pair(5, "E"));
	m.insert(make_pair(6, "F"));
	m.insert(make_pair(7, "G"));

	//遍历map
	printmap(m);
}


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

运行结果如下:

3.3 map的operator[] ⭐

        map重载了[],且其功能为:

[]内部的参数是键值对的key。

如果map中没有这个元素键值对,则调用insert插入<key,value元素的默认值>,同时返回该键值对的value值。

如果map中有这个元素键值对,则直接插入失败,并且返回该key值对应的value值

3.4 map的应用 

字典:使用map的高效搜索

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
//字典
void test()
{
	map<std::string, std::string> dict;
	dict.insert(pair<std::string, std::string>("sort", "排序"));
	dict.insert(pair<std::string, std::string>("string", "字符串"));
	dict.insert(make_pair("tree", "树"));
	dict.insert(make_pair("apple", "苹果"));
	dict.insert(make_pair("hello", "你好"));
	dict.insert(make_pair("world", "世界"));
	dict.insert(make_pair("map", "地图"));

	while (1)
	{
		cout << "输入你要查找的英文:";
		string s; cin >> s;
		if (dict.find(s) != dict.end())
		{
			//此时肯定存在,直接调用[]获取value
			cout << dict[s] << endl;
		}
		else
			cout << "字典没有这个数据" << endl;
	}

}


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

统计:使用高效搜索,和键值对

 

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
//字典
void test()
{
	string s = ")(*&^%$#dfsaghnia1r911476975b3469278677;op'.[8.-'7-8=8911123cr91132c111c98317sdnfsjaNHWE$DRFTGYHUJIWSSSEDRFTGYHUJIK!~@#$%^&*()_@#$%^&*()_jshdgiq9q3@!{}:>?|][;./pol,kimnju87yhbgtrfvch9uhfoqweijqweou]";
	map<char, int> countmap;

	for (const auto& c : s)
	{
		//不存在
		if (countmap.find(c) != countmap.end())
		{
			//存在,该key对应的value+1
			countmap.find(c)->second++;
		}
		else
		{
			//不存在插入这条数据
			countmap.insert(make_pair(c, 1));
		}
	}

	//打印统计结果
	for (const auto& kv : countmap)
		cout << kv.first << ":" << kv.second << "  " ;
}


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

运行结果如下:

当然我们能够使用[]重载的特性,来简化代码 

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
//字典
void test()
{
	string s = ")(*&^%$#dfsaghnia1r911476975b3469278677;op'.[8.-'7-8=8911123cr91132c111c98317sdnfsjaNHWE$DRFTGYHUJIWSSSEDRFTGYHUJIK!~@#$%^&*()_@#$%^&*()_jshdgiq9q3@!{}:>?|][;./pol,kimnju87yhbgtrfvch9uhfoqweijqweou]";
	map<char, int> countmap;

	for (const auto& c : s)
	{
		countmap[c]++;
	}

	//打印统计结果
	for (const auto& kv : countmap)
		cout << kv.first << ":" << kv.second << "  " ;
}


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

四. multiset和multimap 

        这两个容器与set/map的区别就是,这两个容器支持插入重复的数据。且在multimap中一个key可以对应多个value。

使用文档如下:

multiset - C++ Reference (cplusplus.com)

multimap - C++ Reference (cplusplus.com)

相关文章:

  • 【mysql系】mysql启动异常Can‘t create test file localhost.lower-test
  • 【大模型基础_毛玉仁】1.4 语言模型的采样方法
  • Excel中COUNTIF用法解析
  • 【笔记】记一次easyExcel中注解ExcelProperty映射字段赋值无效问题
  • dify 工作流 迭代
  • ArcGIS操作:15 计算点的经纬度,并添加到属性表
  • NDT 代价函数
  • 音视频入门基础:RTP专题(15)——FFmpeg源码中,获取RTP的视频信息的实现
  • K8S学习之基础十一:k8s中容器钩子
  • 日新F1、瑞研F600P 干线光纤熔接(熔接损耗最大0.03DB)
  • three学习记录
  • 秋云 ucharts echarts 高性能跨全端图表组件导入
  • P1443 马的遍历(BFS)
  • 企业日常工作中常用的 Linux 操作系统命令整理
  • Vue 与 Element UI 深度探秘:从 Array.isArray 到动态绑定的技术之旅!✨
  • HTML 表单 (form) 的作用解释
  • 【STM32F103ZET6——库函数】11.捕获红外信号
  • Linux基本操作指令1
  • WPS工具栏添加Mathtype加载项
  • 【网络】IP地址的分类
  • 美国失去最后的AAA主权评级,继标普、惠誉后再遭穆迪降级
  • 中国纪检监察刊文:力戒形式主义官僚主义关键是要坚持实事求是
  • 当智慧农场遇见绿色工厂:百事如何用科技留住春天的味道?
  • 美联储官员:美国经济增速可能放缓,现行关税政策仍将导致物价上涨
  • 北方将现今年首场大范围高温天气,山西河南山东陕西局地可超40℃
  • 临港新片区将新设5亿元启航基金:专门投向在临港发展的种子期、初创型企业