关联式容器
- 在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。
- 关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。
键值对
- 用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。
树形结构的关联式容器
- 应用场景的不同,STL实现了两种不同结构的管理式容器:树型结构与哈希结构。
- 树型结构的关联式容器主要有四种:map、set、multimap、multiset。
- 这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。
set、multiset
set
- set底层是搜索二叉树…
- 实现对数据的去重。 set中查找某个元素,时间复杂度为:logN。
- 排序一般用vector ,和 算法里面的 sort 来实现。
multiset
- multiset允许重复, 可以把里面相同的数据找出来。
- 中序遍历:比如 6 ,要查找中序的第一个6。找到6以后不能停止:
- 要继续看6的左孩子是不是6,不是则返回当前这个6;
- 如果是,取左边的6,继续刚才1.的判断。
#include<iostream>
#include<string>
#include<set>
using namespace std;
void test1()
{
//排序+去重
set<int> s1;
set<string> s2 = { "auto","bad","construction","auto" };
s1.insert(1);
s1.insert(2);
s1.insert(1);
s1.insert(2);
s1.insert(3);
s1.insert(6);
for (auto& i : s1)
{
cout << i << " ";
}
cout << endl;
for (auto& i : s2)
{
cout << i << " ";
}
cout << endl;
multiset<int> s3;
s3.insert(1);
s3.insert(2);
s3.insert(1);
s3.insert(2);
s3.insert(3);
s3.insert(6);
for (auto& i : s3)
{
cout << i << " ";
}
cout << endl;
auto it = s3.find(2);
while (it!=s3.end()&& *it==2)
{
cout << *it <<" ";
++it;
}
cout << endl;
cout << s3.count(1) <<"个 1 "<< endl;
}
int main()
{
test1();
return 0;
}
map、multimap
pair-类模板
- 对键值对的封装,显式声明使用的类型。
emplate <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)
{}
};
- make_pair --对pair使用的简写
make_pair (T1 x, T2 y) = pair<T1,T2>(x,y);
例子: 会让编译器自动推pair的类型
make_pair("nnd",10) = pair<string,int>("nnd",10)
map的【】重载
- 给一个key_type的值,返回的是对应的mapped_type的值的引用
- 原理:先进行插入:
- 没有该元素,则插入,对应的mapped_type给该类型的缺省值;返回的是 mapped_type缺省值的引用。
- 有,也返回key_type值对应的mapped_type的值的引用。
mapped_type& operator[](const Key_Type& K)
{
pair<iterator, bool> ret = insert(make_pair(K, mapped_type()));
return ret.first->second;
}
map
- 把键值对封装成一个pair结构体类型:
typedef pair<const Key, T> value_type;
- map支持下标访问符,即在[]中放入key,返回的是与key对应的value。
- map中的元素按照key类型来排序的,缺省情况下是小于。
- multimap允许冗余。
map插入:统计单词出现次数的三种方法
- 插入成功,返回有 指向那个元素的迭代器和true;
- 失败,说明已经有了该元素,则返回那个元素的迭代器和false;
- 迭代器的类型是 :
pair<key_type,mapped_type>*
结构体(类)类型的指针了属于是。
统计字符串次数
void test2()
{
//k v 是一个pair结构体类型
string str[] = { "nnd","xdm","yyds","xdm" };
map<string, int> m1; //key -- string Value ---- int 不允许有冗余
---// 3.0
for (auto& i : str)
{
//库函数中如果插入成功,则返回 i 的迭代器 和 true pair<iterator,bool>
auto it = m1.insert(make_pair(i, 1));
//= pair<map<string, int>::iterator, bool> ret = m1.insert(make_pair(i, 1));
if (it.second==false)
//假说明存在了 it.first = iterator -> pari<string, int> int =second
{
it.first->second++;
}
}
for (auto& i : m1)
{
cout << i.first << " " << i.second<<endl;
}
---// 2.0
for (auto& i : str)
{
m1[i]++; / /会先进行查找,有相同的K值,则返回对应V值的引用
/ / 没有K值,则进行插入,对应的V值设置成改类型的缺省参数 int() = 0;
}
for (auto& i : m1)
{
cout << i.first << " " << i.second<<endl;
}
for (auto& i : m1)
{
cout << i.first << " ";
}
---// 1.0
for (auto& i : str)
{
auto it = m1.find(i); //找不到返回 end位置的迭代器
if (it!=m1.end()) / /说明里面有这个单词
{
(*it).second++;
it->second++;
}
else
{
m1.insert(make_pair(i,1));
}
}
for (auto& i : m1) //
{
cout << i.first << " " << i.second<<endl;
}
}
map[]
的使用
- 和数组的使用差不多…
void test3()
{
map<string, string> mp;
mp["the truth"] = "is rarely pure";
mp["container"] = "容器";
mp["mp range"] = "范围";
mp["constructs"] = "构造";
for (auto& i : mp)
{
cout << i.first << " <- means -> " << i.second << endl;
}
cout << endl; //默认是按K值排序
}