目录
一 关联式容器(KV模型)
用关联式容器
来存储数据,与序列式容器不同的是,其
里面存储的是
<key, value>
结构的键值对,在
数据检索时比序列式容器效率更高。
二 键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量
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
。这四种容器的共同点是:使用平衡搜索树
(
即红黑树
) 作为其底层结构,容器中的元素是一个有序的序列。
1 set
1.1 set的基本概念与注意事项
① 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
的迭代器遍历
set
中的元素,可以得到有序序列
⑤ set
中的元素默认按照小于来比较
⑥ set
中查找某个元素,时间复杂度为:O(log2N)
⑦ set
中的元素不允许修改,因为Value就是它的键,随意修改会破坏树的结构。
⑧ set
中的底层使用二叉搜索树
(
红黑树
)
来实现。
1.2 set的遍历
set<int> s;
s.insert(10);
s.insert(1);
s.insert(99);
s.insert(101);
s.insert(50);
s.insert(10);
s.insert(6);
s.insert(55);
s.insert(10);
//遍历方式一 迭代器
//排序加去重
set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//降序
set<int>::reverse_iterator it1 = s.rbegin();
while (it1 != s.rend())
{
cout << *it1 << " ";
it1++;
}
cout << endl;
//遍历方法二 范围for(基于迭代器)
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
1.3 set 的查找与删除
//查找
set<string> sstr;
sstr.insert("sort");
sstr.insert("add");
sstr.insert("sum");
sstr.insert("adjust");
sstr.insert("list");
set<string>::iterator iter = sstr.find("list");
if (iter != sstr.end())
{
cout << "找到了" << *iter << endl;
}
else
{
cout << "没找到" << endl;
}
//因为set底层为搜索二叉树KEY模型,所以不支持随便更改数据的值,否则可能会破坏结构
//删除
auto pos = sstr.find("sort");
sstr.erase(pos);
sstr.erase("list");
2 multiset
与set的区别是,multiset中的元素可以重复,set是中value是唯一的。
3 map
3.1 概念
① map
是关联容器,它按照特定的次序
(
按照
key
来比较
)
存储由键值
key
和值
value
组合而成的元素。
②
在
map
中,
键值key通常用于排序和惟一地标识元素
,而值
value
中存储与此键值
key
关联的内容。键值key和值
value
的类型可能不同,并且在
map
的内部,
key
与
value
通过成员类型
value_type
绑定在一起,为其取别名称为pair: typedef pair value_type;
③
在内部,
map
中的元素总是按照键值
key
进行比较排序的。
④ map
中通过键值访问单个元素的速度通常比
unordered_map
容器慢,但
map
允许根据顺序对元素进行直接迭代(
即对
map
中的元素进行迭代时,可以得到一个有序的序列
)
。
⑤
map支持下标访问符,即在[]中放入key,就可以找到与key对应的value
。
⑥ map
通常被实现为二叉搜索树
(
更准确的说:平衡二叉搜索树
(
红黑树
))
。
3.2 map的迭代器遍历方式
//map的基本使用
void map_test(void)
{
map<int, double> m;
//调用pair的构造函数,构造一个匿名对象插入
m.insert(pair<int, double>(1, 8.9));
m.insert(pair<int, double>(5, 45.4));
m.insert(pair<int, double>(7, 9.0));
m.insert(pair<int, double>(2, 8.9));
m.insert(pair<int, double>(3, 7.8));
m.insert(pair<int, double>(7, 6.9));//插入不成功,键值相同
//调用函数模板构造对象。
//好处:不需要去声明pair的参数,让函数自己推演,用起来方便
m.insert(make_pair(7, 6.9));
//迭代器遍历
map<int, double>::iterator it = m.begin();
while (it != m.end())
{
//cout << (*it).first << ":" << (*it).second << " ";
cout << it->first << ":" << it->second << " ";
it++;
}
cout << endl;
}
3.3 简化嵌套结构
//简化嵌套结构
void map_test1(void)
{
typedef std::map<std::string, std::string> DICT;
typedef std::pair<std::string, std::string> DICT_KV;
typedef std::map<std::string, std::string>::iterator DICT_IT;
//std::map<std::string,std::string> dic;
DICT dic;
//dic.insert(std::pair<std::string, std::string>("insert", "插入"));
//dic.insert(std::pair<std::string, std::string>("sort", "排序"));
//dic.insert(std::pair<std::string, std::string>("find", "查找"));
dic.insert(DICT_KV("insert", "插入"));
dic.insert(DICT_KV("sort", "排序"));
dic.insert(DICT_KV("find", "查找"));
dic.insert(DICT_KV("left", "左边"));
DICT_IT dit = dic.begin();
while (dit != dic.end())
{
//key值不可修改,但是value可以修改
dit->second.insert(0, "{");
dit->second += "}";
cout << dit->first << "--" << dit->second << endl;
dit++;
}
auto ret = dic.find("left");
if(ret != dic.end())
{
//可读性优化
string& str = ret->second;
str.insert(str.size() - 1, "、剩余");
}
cout << endl;
dit = dic.begin();
while (dit != dic.end())
{
cout << dit->first << "--" << dit->second << endl;
dit++;
}
}
3.4 统计水果出现次数
//统计水果出现次数
void map_test2(void)
{
思路一
//string arr[] = { "苹果","苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "香蕉", "苹果", "苹果" };
//std::map<std::string, int> countMap;
//for (const auto& str : arr)
//{
// std::map<std::string, int>::iterator it = countMap.find(str);
// //找到了就不是第一次出现,数量加加
// if (it != countMap.end())
// {
// it->second++;
// }
// //没找到,第一次出现,插入
// else
// {
// countMap.insert(make_pair(str,1));
// }
//}
//for (const auto& e : countMap)
//{
// cout << e.first << "--" << e.second << endl;
//}
思路二
//string arr[] = { "苹果","苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
//std::map<std::string, int> countMap;
//for (const auto& str : arr)
//{
// auto ret = countMap.insert(make_pair(str, 1));
// if(ret.second==false)
// {
// ret.first->second++;
// }
//}
//for (const auto& e : countMap)
//{
// cout << e.first << "--" << e.second << endl;
//}
//思路三
string arr[] = { "苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
map<string, int> countMap;
for (const auto& str : arr)
{
countMap[str]++;
}
for (const auto& e : countMap)
{
cout << e.first << "--" << e.second << endl;
}
}
3.5 [ ]的重载使用
//[key],key为结点键值,[key]会返回结点的value的引用
void map_test3(void)
{
map<string,string> sortmap;
sortmap.insert(make_pair("left", "左边"));
cout << sortmap["left"] << endl;
//插入right,value为右边。
sortmap["right"] = "右边";
//插入sort,value为缺省值
sortmap["sort"];
sortmap["insert"] = "插入";
sortmap["left"] += "、剩余";
cout << sortmap["left"] << endl;
}
3.6 topK问题
//TOPK问题
struct MapItCompare
{
bool operator()(map<string, int>::iterator x, map<string, int>::iterator y)
{
return x->second > y->second;
}
};
void map_test4(void)
{
string arr[] = { "苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
map<string, int> countMap;
for (const auto& str : arr)
{
countMap[str]++;
}
//for (const auto& e : countMap)
//{
// cout << e.first << "--" << e.second << endl;
//}
//排序一
vector<map<string, int>::iterator> v1;
map<string, int>::iterator countMapIt = countMap.begin();
while (countMapIt != countMap.end())
{
v1.push_back(countMapIt);
countMapIt++;
}
sort(v1.begin(),v1.end(),MapItCompare());
//排序二
//map<int, string,greater<int>> sortMap;//降序
map<int, string> sortMap;//升序
for (auto e : countMap)
{
sortMap.insert(make_pair(e.second, e.first));
}
for (auto e : sortMap)
{
cout << e.second << "--" << e.first << endl;
}
}
4 multimap
multimap和map的区别:①map中的key是唯一的,而multimap中key是可以重复的。
②multimap中没有重载operator[]操作,因为键值可以重复