set就是key模型的搜索树
map就是key_value模型的搜索树
但是他们的底层不是搜索二叉树,是AVL树和红黑树!
map和set insert不会迭代器失效
erase会迭代器失效
1.set
1.1 set及使用
T: set中存放元素的类型,实际在底层存储<value, value>的键值对。
Compare:set中元素默认按照小于来比较
Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理
- set是按照一定次序存储元素的容器
- 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。
set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。- 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行 排序。
- set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对 子集进行直接迭代。
- set在底层是用二叉搜索树(红黑树)实现的
- 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放
value,但在底层实际存放的是由<value, value>构成的键值对。- set中插入元素时,只需要插入value即可,不需要构造键值对。
- set中的元素不可以重复(因此可以使用set进行去重)。
set的一些使用如下:
1.2 multiset及使用
multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。这就是和set最大的区别!
2.map
2.1 map及使用
- map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元 素。
- 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的 内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型
value_type绑定在一起,为其取别名称为pair: typedef pair<const key, T> value_type;- 在内部,map中的元素总是按照键值key进行比较排序的。
- map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序 对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
- map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
map允许修改迭代器,如下图value_type就是一个pair!所以pair<k,v>相当于这样存!
所以insert的时候就要注意,其使用如下:
#include<iostream>
#include<map>
#include<vector>
using namespace std;
void test_map1()
{
map<string, string> dict;
pair<string, string> kv1("sort", "排序");
dict.insert(kv1);//1.定义有名对象
dict.insert(pair<string, string>("left", "左边"));//2.定义匿名对象
dict.insert(make_pair("right", "右边"));//3.make_pair定义(函数模板)
dict.insert(make_pair("right", "xxxx"));
//pair<string, string> kv2 = { "string", "字符串" }; // 4.隐式类型转换
dict.insert({ "string", "字符串" });
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();
while (it != dict.end())
{
// iterator key不能修改 value可以修改
// const_iterator key不能修改 value不能修改
//it->first += 'x';//first不能修改,second可以修改
it->second += 'x';
//cout << *it << " ";//这样是不行的,因为有一个key有一个value!
//cout << (*it).first << ":" << (*it).second << endl;//可以
cout << it->first << ":" << it->second << endl;//写全如下↓
//cout << it.operator->()->first << ":" << it.operator->()->second << endl;
++it;
}
cout << endl;
for (auto& kv : dict)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
//map<string, string> dict2 = { {"string", "字符串"}, {"left", "左边"},{"right", "右边"} };
map<string, string> dict2 = { kv1, {"left", "左边"},{"right", "右边"} };
}
int main()
{
test_map1();
return 0;
}
void test_map2()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" };
map<string, int> countMap;
for (auto& e : arr)
{
//统计方法1
countMap[e]++;
//统计方法2
//auto it = countMap.find(e);
//if (it != countMap.end())
//{
// it->second++;
//}
//else
//{
// //const pair<string, int>& val = { e, 1 };
// countMap.insert({ e, 1 });
//}
}
for (auto& kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
//对次数排序
multimap<int, string> sortMap;//使用multimap是因为其可以冗余,map不能冗余会发生数据丢失
for (auto& kv : countMap)
{
//sortMap[kv.second] = kv.first;
sortMap.insert({ kv.second, kv.first });
}
cout << endl;
for (auto& kv : sortMap)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
int main()
{
test_map2();
return 0;
}
void test_map3()
{
map<string, string> dict;
dict.insert({ "string", "字符串" });
// 插入(一般不会这么用)
dict["right"];
// 插入+修改
dict["left"] = "左边";
// "查找"
cout << dict["string"] << endl;
// 修改
dict["right"] = "右边";
string str;
cin >> str;
if (dict.count(str))
{
cout << "在" << endl;
}
else
{
cout << "不在" << endl;
}
}
2.2 multimap及使用
与map最大区别就是可以有数据冗余!其中元素是可以重复的!
见上面的排序!
3.关于operator[]
对于其使用可以来看下面两道例题:
3.1 例一
class Solution {
public:
struct kvcom
{
bool operator()(const pair<string,int>&kv1,const pair<string,int>&kv2)
{
//降序排列,从大到小排列
return kv1.second > kv2.second ||
(kv1.second==kv2.second && kv1.first < kv2.first);
}
};
vector<string> topKFrequent(vector<string>& words, int k)
{
map<string,int> countMap;
for(auto& e:words)
{
countMap[e]++;
}
vector<pair<string,int>> v(countMap.begin(),countMap.end());
sort(v.begin(),v.end(),kvcom());
vector<string> res;
for(size_t i=0;i<k;i++)
{
cout<<v[i].first<<":"<<v[i].second<<endl;
res.push_back(v[i].first);
}
return res;
}
};
3.2 例二
#include <iostream>
#include <string>
#include <map>
#include <functional>
using namespace std;
//仿函数控制比较
struct comp
{
bool operator()(const pair<string, int>& kv1, const pair<string, int>& kv2)
{
return kv1.second > kv2.second || (kv1.second == kv2.second && kv1.first < kv2.first);
}
};
int main()
{
string s;
getline(cin,s);
for(auto& e:s)
{
if(e>='A' && e<='Z')
e += 32;
}
vector<string> v;
for(int i=0;i<s.size();i++)
{
string tmp;
while(s[i]!=' ' && s[i]!='.')
{
tmp += s[i];
i++;
}
v.push_back(tmp);
}
map<string,int> m;
for(auto& e:v)
{
m[e]++;
}
//sort+仿函数排序
vector<pair<string, int>> vv(m.begin(), m.end());
sort(vv.begin(), vv.end(), comp());
for (int i = 0; i < vv.size(); ++i)
{
cout << vv[i].first << ":" << vv[i].second << endl;
}
return 0;
}