目录
在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、
forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是
结构的键值对,在数据检索时比序列式容器效率更高 。
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息
SGI-STL中关于键值对的定义:
template <class T1, class T2> struct pair { typedef T1 first_type; typedef T2 second_type; T1 first; T2 second; pair() : first(T1()), second(T2()) {} pair(const T1& a, const T2& b) : first(a), second(b) {} };
根据应用场景的不桶,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结 构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。下面一依次介绍每一个容器。
set文档介绍链接:set - C++ Reference
简介:
本质:
set和multiset区别
功能描述:创建set容器以及赋值
构造:
set st; //默认构造函数:set(const set &st); //拷贝构造函数赋值:
set& operator=(const set &st); //重载等号操作符- #include
- #include
- using namespace std;
- #include
-
- void printSet(set<int> & s)
- {
- for (set<int>::iterator it = s.begin(); it != s.end(); it++)
- {
- cout << *it << " ";
- }
- cout << endl;
- }
-
- //构造和赋值
- void test01()
- {
- set<int> s1;
-
- s1.insert(10);
- s1.insert(30);
- s1.insert(20);
- s1.insert(40);
- printSet(s1);
-
- //拷贝构造
- set<int>s2(s1);
- printSet(s2);
-
- //赋值
- set<int>s3;
- s3 = s2;
- printSet(s3);
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
输出:
10 20 30 40
10 20 30 40
10 20 30 40
总结:
功能描述:
函数原型:
size(); //返回容器中元素的数目empty(); //判断容器是否为空swap(st); //交换两个集合容器示例:
- #include
- #include
- using namespace std;
- #include
-
- void printSet(set<int> & s)
- {
- for (set<int>::iterator it = s.begin(); it != s.end(); it++)
- {
- cout << *it << " ";
- }
- cout << endl;
- }
-
- //大小
- void test01()
- {
-
- set<int> s1;
-
- s1.insert(10);
- s1.insert(30);
- s1.insert(20);
- s1.insert(40);
-
- if (s1.empty())
- {
- cout << "s1为空" << endl;
- }
- else
- {
- cout << "s1不为空" << endl;
- cout << "s1的大小为: " << s1.size() << endl;
- }
-
- }
-
- //交换
- void test02()
- {
- set<int> s1;
-
- s1.insert(10);
- s1.insert(30);
- s1.insert(20);
- s1.insert(40);
-
- set<int> s2;
-
- s2.insert(100);
- s2.insert(300);
- s2.insert(200);
- s2.insert(400);
-
- cout << "交换前" << endl;
- printSet(s1);
- printSet(s2);
- cout << endl;
-
- cout << "交换后" << endl;
- s1.swap(s2);
- printSet(s1);
- printSet(s2);
- }
-
- int main() {
-
- test01();
-
- test02();
-
- return 0;
- }
输出:
s1不为空
s1的大小为: 4
交换前
10 20 30 40
100 200 300 400交换后
100 200 300 400
10 20 30 40
功能描述:
函数原型:
insert(elem); //在容器中插入元素。clear(); //清除所有元素erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。erase(elem); //删除容器中值为elem的元素。- #include
- #include
- using namespace std;
- #include
-
- void printSet(set<int> & s)
- {
- for (set<int>::iterator it = s.begin(); it != s.end(); it++)
- {
- cout << *it << " ";
- }
- cout << endl;
- }
-
- //插入和删除
- void test01()
- {
- set<int> s1;
- //插入
- s1.insert(10);
- s1.insert(30);
- s1.insert(20);
- s1.insert(40);
- printSet(s1);
-
- //删除
- s1.erase(s1.begin());
- printSet(s1);
-
- s1.erase(30);
- printSet(s1);
-
- //清空
- //s1.erase(s1.begin(), s1.end());
- s1.clear();
- printSet(s1);
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
10 20 30 40
20 30 40
20 40
功能描述:
函数原型:
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();count(key); //统计key的元素个数- #include
- #include
- using namespace std;
- #include
-
- //查找和统计
- void test01()
- {
- set<int> s1;
- //插入
- s1.insert(10);
- s1.insert(30);
- s1.insert(20);
- s1.insert(40);
-
- //查找
- set<int>::iterator pos = s1.find(30);
-
- if (pos != s1.end())
- {
- cout << "找到了元素 : " << *pos << endl;
- }
- else
- {
- cout << "未找到元素" << endl;
- }
-
- //统计
- int num = s1.count(30);
- cout << "num = " << num << endl;
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
找到了元素 : 30
num = 1
学习目标:
区别:
- #include
- #include
- using namespace std;
- #include
-
- //set和multiset区别
- void test01()
- {
- set<int> s;
- pair
int>::iterator, bool> ret = s.insert(10); - if (ret.second) {
- cout << "第一次插入成功!" << endl;
- }
- else {
- cout << "第一次插入失败!" << endl;
- }
-
- ret = s.insert(10);
- if (ret.second) {
- cout << "第二次插入成功!" << endl;
- }
- else {
- cout << "第二次插入失败!" << endl;
- }
-
- //multiset
- multiset<int> ms;
- ms.insert(10);
- ms.insert(10);
-
- for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) {
- cout << *it << " ";
- }
- cout << endl;
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
输出:
第一次插入成功!
第二次插入失败!
10 10
总结:
1. set是按照一定次序存储元素的容器
2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。
set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对
子集进行直接迭代。
5. set在底层是用二叉搜索树(红黑树)实现的。
注意:
1. 与map/multimap不同,map/multimap中存储的是真正的键值对
,set中只放 value,但在底层实际存放的是由
构成的键值对 。2. set中插入元素时,只需要插入value即可,不需要构造键值对。
3. set中的元素不可以重复(因此可以使用set进行去重)。
4. 使用set的迭代器遍历set中的元素,可以得到有序序列
5. set中的元素默认按照小于来比较
6. set中查找某个元素,时间复杂度为:log2 N
7. set中的元素不允许修改(为什么?)
8. set中的底层使用二叉搜索树(红黑树)来实现
功能描述:
两种创建方式:
pair p ( value1, value2 ); pair p = make_pair( value1, value2 ); - #include
- #include
- using namespace std;
- //对组创建
- void test01()
- {
- pair
int > p(string("Tom"), 20); - cout << "姓名: " << p.first << " 年龄: " << p.second << endl;
-
- pair
int> p2 = make_pair("Jerry", 10); - cout << "姓名: " << p2.first << " 年龄: " << p2.second << endl;
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
输出:
姓名: Tom 年龄: 20
姓名: Jerry 年龄: 10
改变排序顺序核心
- class MyCompare
- {
- public:
- bool operator()(int v1, int v2) {
- return v1 > v2;
- }
- };
- #include
- #include
- using namespace std;
- #include
-
- class MyCompare
- {
- public:
- bool operator()(int v1, int v2) {
- return v1 > v2;
- }
- };
- void test01()
- {
- set<int> s1;
- s1.insert(10);
- s1.insert(40);
- s1.insert(20);
- s1.insert(30);
- s1.insert(50);
-
- //默认从小到大
- for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
- cout << *it << " ";
- }
- cout << endl;
-
- //指定排序规则
- set<int,MyCompare> s2;
- s2.insert(10);
- s2.insert(40);
- s2.insert(20);
- s2.insert(30);
- s2.insert(50);
-
- for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {
- cout << *it << " ";
- }
- cout << endl;
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
输出:
10 20 30 40 50
50 40 30 20 10
利用仿函数可以指定set容器的排序规则
- #include
- #include
- using namespace std;
- #include
-
- class Person
- {
- public:
- Person(string name, int age)
- {
- this->m_Name = name;
- this->m_Age = age;
- }
-
- string m_Name;
- int m_Age;
-
- };
- class comparePerson
- {
- public:
- bool operator()(const Person& p1, const Person &p2)
- {
- //按照年龄进行排序 降序
- return p1.m_Age > p2.m_Age;
- }
- };
-
- void test01()
- {
- set
s; -
- Person p1("刘备", 23);
- Person p2("关羽", 27);
- Person p3("张飞", 25);
- Person p4("赵云", 21);
-
- s.insert(p1);
- s.insert(p2);
- s.insert(p3);
- s.insert(p4);
-
- for (set
::iterator it = s.begin(); it != s.end(); it++) - {
- cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;
- }
- }
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
输出:
姓名: 关羽 年龄: 27
姓名: 张飞 年龄: 25
姓名: 刘备 年龄: 23
姓名: 赵云 年龄: 21
对于自定义数据类型,set必须指定排序规则才可以插入数据
map的文档简介链接:map - C++ Reference
简介:
本质:
优点:
map和multimap区别:
功能描述:
函数原型:
构造:
map mp; //map默认构造函数:map(const map &mp); //拷贝构造函数赋值:
map& operator=(const map &mp); //重载等号操作符示例:
- #include
- #include
- using namespace std;
- #include
-
- void printMap(map<int,int>&m)
- {
- for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
- {
- cout << "key = " << it->first << " value = " << it->second << endl;
- }
- cout << endl;
- }
-
- void test01()
- {
- map<int,int>m; //默认构造
- m.insert(pair<int, int>(1, 10));
- m.insert(pair<int, int>(2, 20));
- m.insert(pair<int, int>(3, 30));
- printMap(m);
-
- map<int, int>m2(m); //拷贝构造
- printMap(m2);
-
- map<int, int>m3;
- m3 = m2; //赋值
- printMap(m3);
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
-
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30key = 1 value = 10
key = 2 value = 20
key = 3 value = 30key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
map中所有元素都是成对出现,插入数据时候要使用对组
功能描述:
函数原型:
size(); //返回容器中元素的数目empty(); //判断容器是否为空swap(st); //交换两个集合容器- #include
- #include
- using namespace std;
- #include
-
- void printMap(map<int,int>&m)
- {
- for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
- {
- cout << "key = " << it->first << " value = " << it->second << endl;
- }
- cout << endl;
- }
-
- void test01()
- {
- map<int, int>m;
- m.insert(pair<int, int>(1, 10));
- m.insert(pair<int, int>(2, 20));
- m.insert(pair<int, int>(3, 30));
-
- if (m.empty())
- {
- cout << "m为空" << endl;
- }
- else
- {
- cout << "m不为空" << endl;
- cout << "m的大小为: " << m.size() << endl;
- }
- }
-
-
- //交换
- void test02()
- {
- map<int, int>m;
- m.insert(pair<int, int>(1, 10));
- m.insert(pair<int, int>(2, 20));
- m.insert(pair<int, int>(3, 30));
-
- map<int, int>m2;
- m2.insert(pair<int, int>(4, 100));
- m2.insert(pair<int, int>(5, 200));
- m2.insert(pair<int, int>(6, 300));
-
- cout << "交换前" << endl;
- printMap(m);
- printMap(m2);
-
- cout << "交换后" << endl;
- m.swap(m2);
- printMap(m);
- printMap(m2);
- }
-
- int main() {
-
- test01();
-
- test02();
-
- system("pause");
-
- return 0;
- }
-
m不为空
m的大小为: 3
交换前
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30key = 4 value = 100
key = 5 value = 200
key = 6 value = 300交换后
key = 4 value = 100
key = 5 value = 200
key = 6 value = 300key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
功能描述:
函数原型:
insert(elem); //在容器中插入元素。clear(); //清除所有元素erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。erase(key); //删除容器中值为key的元素。- #include
- #include
- using namespace std;
- #include
-
- void printMap(map<int,int>&m)
- {
- for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
- {
- cout << "key = " << it->first << " value = " << it->second << endl;
- }
- cout << endl;
- }
-
- void test01()
- {
- //插入
- map<int, int> m;
- //第一种插入方式
- m.insert(pair<int, int>(1, 10));
- //第二种插入方式
- m.insert(make_pair(2, 20));
- //第三种插入方式
- m.insert(map<int, int>::value_type(3, 30));
- //第四种插入方式
- m[4] = 40;
- printMap(m);
-
- //删除
- m.erase(m.begin());
- printMap(m);
-
- m.erase(3);
- printMap(m);
-
- //清空
- m.erase(m.begin(),m.end());
- m.clear();
- printMap(m);
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
-
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40key = 2 value = 20
key = 3 value = 30
key = 4 value = 40key = 2 value = 20
key = 4 value = 40
功能描述:
函数原型:
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();count(key); //统计key的元素个数- #include
- #include
- using namespace std;
- #include
-
- //查找和统计
- void test01()
- {
- map<int, int>m;
- m.insert(pair<int, int>(1, 10));
- m.insert(pair<int, int>(2, 20));
- m.insert(pair<int, int>(3, 30));
-
- //查找
- map<int, int>::iterator pos = m.find(2);
-
- if (pos != m.end())
- {
- cout << "找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl;
- }
- else
- {
- cout << "未找到元素" << endl;
- }
-
- //统计
- int num = m.count(3);
- cout << "num = " << num << endl;
- }
-
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
找到了元素 key = 2 value = 20
num = 1
- #include
- #include
- using namespace std;
- #include
-
- class MyCompare {
- public:
- bool operator()(int v1, int v2) {
- return v1 > v2;
- }
- };
-
- void test01()
- {
- //默认从小到大排序
- //利用仿函数实现从大到小排序
- map<int, int, MyCompare> m;
-
- m.insert(make_pair(1, 10));
- m.insert(make_pair(2, 20));
- m.insert(make_pair(3, 30));
- m.insert(make_pair(4, 40));
- m.insert(make_pair(5, 50));
-
- for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
- cout << "key:" << it->first << " value:" << it->second << endl;
- }
- }
- int main() {
-
- test01();
-
- system("pause");
-
- return 0;
- }
key:5 value:50
key:4 value:40
key:3 value:30
key:2 value:20
key:1 value:10
1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的
内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型
value_type绑定在一起,为其取别名称为pair: typedef pair
value_type; 3. 在内部,map中的元素总是按照键值key进行比较排序的。
4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序
对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
注意:multimap与map最大区别就是不支持operator[]传值(key的唯一性)

利用set去重并排序
- class Solution {
- public:
- vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
- set<int> s1;
- for(auto e:nums1) s1.insert(e);
-
- set<int> s2;
- for(auto e:nums2) s2.insert(e);
-
- vector<int> v;
-
- for(auto e1:s1)
- {
- if(s2.count(e1)) v.push_back(e1);
- }
- return v;
- }
- };
经典哈希表存储频数方法
- class Solution {
- public:
- int firstUniqChar(string s) {
- map<int,int> m;
- for(auto ch:s) m[ch]++;
-
- for(int i=0;i
size();i++) - {
- if(m[s[i]]==1) return i;
- }
- return -1;
- }
- };

对于map的范围for:
- map<int,string> mp;
- for(auto [key值,value值] : mp)
- class Solution {
- public:
- int singleNumber(vector<int>& nums) {
- map<int,int> m;
- for(int n:nums)
- {
- m[n]++;
- }
- int ret;
- for(auto [n,ac]:m)
- {
- if(ac==1)
- {
- ret=n;
- break;
- }
- }
- return ret;
- }
-
- };

- class Solution {
- public:
- bool canPermutePalindrome(string s) {
- unordered_map<char, int> tempMP;
- for (char c:s) {
- tempMP[c]++;
- }
- int time = 0; //记录奇数次字母的个数
- for (auto [first, second] : tempMP) {
- if (second % 2)
- {
- if(++time > 1) return false;//若超过1个则不可能对称形成回文
- }
- }
- return true;
- }
- };
-
