1. 背景概念
1.1 键值对
用来表示具有一一对应关系的结构,一般包含两个成员变量,key和value
template <class T1, class T2>
struct pair
{
T1 first;
T2 second;
pair()
:first(T1()),second(T2())
{}
pair(const T1& a, const T2& b)
: first(a), second(b)
{}
};
1.2 关联式容器
存储的是<key,value>结构的键值对。一一对应,所以数据检索的效率高。
1.3 树形关联式容器
map、set、multimap、multiset。底层使用的是平衡搜索树(红黑树),容器中的元素是一个有序的序列。
2. set
2.1 set简介
- set是按照一定次序存储元素的容器。
- 不允许冗余数据,所以可以去重。因为有序,数据不能修改。
- 可以插入可以删除
- 默认排升序
- set中只放value,但在底层实际存放的是由<key,key>构成的键值对
- 没有支持operator[]
2.2 set的使用
2.2.1 构造set
#include<set>
using namespace std;
int main()
{
// 1234567
set<int>s1;
s1.insert(1);s1.insert(2);s1.insert(3);//...
set<int>s2={1,2,3,4,5,6,7};
int a[]={1,2,3,4,5,6,7};
set<int>s3(a,a+sizeof(a)/sizeof(int));
return 0;
}
2.2.2 使用迭代器更新
string str={sadhjwiajh};
set<char> s4(str.begin(),str.end());
打印
void print(set<int>& s)
{
set<int>::iterator it = s.begin();
while (it != s.end())
{
//*it = 10;
cout << *it << " ";
++it;
}
cout << endl;
}
2.2.3 升序和降序
默认都排升序
#include<set>
using namespace std;
void test2()
{
set<int>s1={9,5,6,2,4,1,8};//升序
//great<int>的使用需要包含头文件 #include <functional>
set<int,great<int>> s2={9,5,6,2,4,1,8};//降序
//print(s2);这里会传参报错 还是手动打印
set<int>::iterator it = s2.begin();
while (it != s2.end())
{
//*it = 10;
cout << *it << " ";
++it;
}
cout << endl;
}
2.2.4 修改
s1.insert(value);//插入value
s1.erase(value);//删除值为value的键值对,返回删除的元素的个数
s1.erase(iterator first,iterator last);//删除 迭代器区间[first,last)区间中的元素
set<int>::iterator pos=s1.find(20);
if(pos!=s1.end())
s1.earese(pos);//删除迭代器值为pos的键值对
2.2.5 统计
s1.count(val);//返回值为value的元素个数,不存在返回0
2.2.6 lower_bound upper_bound
lower_bound(value);//返回>=value的值的迭代器
upper_bound(value);//返回>value的值得迭代器
void test3()
{
std::set<int> myset;
std::set<int>::iterator itlow, itup;
for (int i = 1; i < 10; i++)
myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90
itlow = myset.lower_bound(25); // >= val
itup = myset.upper_bound(60); // > val
cout << "["<<*itlow <<","<<*itup<<"]"<<endl;
myset.erase(itlow, itup); // 10 20 70 80 90
print(myset);
}
3. multiset
3.1 multiset介绍
- 支持数据冗余。即不能去重。
- 构造方法同set。
- 使用find(value)函数时,返回的是中序遍历中第一个value值对应的键值对的迭代器。
- 使用erase(value)时,删除所有的value值对应的键值对。
4. map
在内部,map中的元素总是按照键值key进行比较排序的
map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序
对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列
map支持下标访问符,即在[]中放入key,就可以找到与key对应的value
map默认以key的升序排列
key不能直接修改
4.1 map的使用
打印
写法一
map<string, string>::iterator it = dict.begin();
//auto it = dict1.begin();
while (it != dict1.end())
{
//cout << (*it).first << (*it).second <<endl;
cout << it->first << it->second << endl;
++it;
}
cout << endl;
写法二
for (const auto& kv : dict1)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
4.1.1 插入数据
方法一 实例化pair对象
map<string, string>dict1;
pair<string, string>kv1("sort", "排序");
dict1.insert(kv1);
方法二 利用匿名对象
dict1.insert(pair<string, string>("left", "左边"));
方法三 make_pair 函数模板
dict1.insert(make_pair("right", "右边"));
4.1.2 map中元素的修改
s1.erase(x);//删除键值为x的键值对,返回删除的元素的个数
s1.erase(iterator first,iterator last);//删除 迭代器区间[first,last)区间中的元素
m1.find(x);//在map中查找key为x的元素,找到返回该位置的迭代器,找不到返回m1.end()
m1.count(x);//返回key为x的键值在map中的个数
4.2 更新value值的方法
方法一
void test5()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果",
"西瓜", "苹果", "香蕉", "苹果", "香蕉","香蕉","香蕉" };
map<string, int>countmap;
for (auto& str : arr)
{
map<string, int>::iterator it = countmap.find(str);
if (it != countmap.end())
{
//(*it).second++;
it->second++;
}
else
{
countmap.insert(make_pair(str,1));
}
}
方法二 operator[]
countmap[key];
在map中寻找key,找了就返回对应pair的value的引用。
找不到就插入一个pair<key,v()>,然后返回v()(value类型的构造函数创建的匿名对象)的引用
void test6()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果",
"西瓜", "苹果", "香蕉", "苹果", "香蕉","香蕉","香蕉" };
map<string, int>countmap;
for (auto& str : arr)
{
countmap[str]++;
//创建"苹果"时,value创建一个int() 默认构造函数给的值是0
//然后 0++ 变成1
}
for (const auto& kv : countmap)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
5.multimap
multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以
重复的。
不支持operator[ ]
6. 在oj中的应用
前K个高频单词
class Solution {
public:
struct less
{
//因为是优先级队列,排降序 要写成排升序
bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2) const
{
if(kv1.second<kv2.second) return true;
if(kv1.second==kv2.second && kv1.first>kv2.first) return true;
// def cde bcd abc
return false;
}
};
vector<string> topKFrequent(vector<string>& words, int k)
{
map<string,int>countmap;
for(auto& str:words)
{
countmap[str]++;
}
priority_queue<pair<string,int>,vector<pair<string,int>>, less> maxmap;
for(auto pair:countmap)
{
maxmap.push(pair);
}
vector<string> result;
while(k--)
{
result.push_back(maxmap.top().first);
maxmap.pop();
}
return result;
}
};
两个数组的交集
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2)
{
// vector<int>result;
// unordered_set<int>m1(nums1.begin(),nums1.end());
// for(auto& e:nums2)
// {
// if(m1.find(e)!=m1.end())
// {
// result.push_back(e);
// }
// }
// return result;
//这样结果会出现 {2,2} 要的是去重之后的结果 {2}
unordered_set<int>result_set;
unordered_set<int>m1(nums1.begin(),nums1.end());
for(auto& e:nums2)
{
if(m1.find(e)!=m1.end())
{
result_set.insert(e);
}
}
return vector<int>(result_set.begin(),result_set.end());
}
};