目录
一、关联式容器
二、键值对
三、树形结构的关联式容器
set/ multiset 容器
set基本概念
set构造和赋值
set大小和交换
set插入和删除
set查找和统计
set和multiset区别
set / multiset总结
pair对组创建
set容器排序
内置类型指定排序规则
自定义数据类型指定排序规则
map/ multimap容器
map基本概念
map构造和赋值
map大小和交换
map插入和删除
map查找和统计
map容器排序
map / multimap总结
OJ练习
在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、
forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是
结构的键值对,在数据检索时比序列式容器效率更高 。
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息
SGI-STL中关于键值对的定义:
template
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 & s)
{
for (set::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//构造和赋值
void test01()
{
set s1;
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
printSet(s1);
//拷贝构造
sets2(s1);
printSet(s2);
//赋值
sets3;
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 & s)
{
for (set::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//大小
void test01()
{
set 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 s1;
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
set 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 & s)
{
for (set::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//插入和删除
void test01()
{
set 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 s1;
//插入
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
//查找
set::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 s;
pair::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 ms;
ms.insert(10);
ms.insert(10);
for (multiset::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 p(string("Tom"), 20);
cout << "姓名: " << p.first << " 年龄: " << p.second << endl;
pair 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 s1;
s1.insert(10);
s1.insert(40);
s1.insert(20);
s1.insert(30);
s1.insert(50);
//默认从小到大
for (set::iterator it = s1.begin(); it != s1.end(); it++) {
cout << *it << " ";
}
cout << endl;
//指定排序规则
set s2;
s2.insert(10);
s2.insert(40);
s2.insert(20);
s2.insert(30);
s2.insert(50);
for (set::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
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
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
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
找到了元素 key = 2 value = 20
num = 1
#include
#include
using namespace std;
#include
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 intersection(vector& nums1, vector& nums2) {
set s1;
for(auto e:nums1) s1.insert(e);
set s2;
for(auto e:nums2) s2.insert(e);
vector v;
for(auto e1:s1)
{
if(s2.count(e1)) v.push_back(e1);
}
return v;
}
};
经典哈希表存储频数方法
class Solution {
public:
int firstUniqChar(string s) {
map m;
for(auto ch:s) m[ch]++;
for(int i=0;i
对于map的范围for:
map mp;
for(auto [key值,value值] : mp)
class Solution {
public:
int singleNumber(vector& nums) {
map m;
for(int n:nums)
{
m[n]++;
}
int ret;
for(auto [n,ac]:m)
{
if(ac==1)
{
ret=n;
break;
}
}
return ret;
}
};
面试题 01.04. 回文排列
class Solution {
public:
bool canPermutePalindrome(string s) {
unordered_map 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;
}
};
692. 前K个高频单词 - 力扣(LeetCode)
单词识别_牛客题霸_牛客网 (nowcoder.com)