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)