关联容器
关联容器:
1、各个容器底层的数据结构 O(1) /O(log2n)
2、常用增删查方法
增加: insert(val)
遍历: iterator自己搜索, 调用find成员方法
删除: erase(key) erase(it)
1、无序关联容器
无序关联容器 =>底层实现是 链式哈希表 增删查的时间复杂度O(1)
set:集合,存储 key
map:映射表,存储 [key,value]键值对
unordered_set 无序的单重集合
unordered_multiset无序的 多重集合
unordered_map 无序的 单重映射表
unordered_multimap 无序的 多重映射表
单重就是不允许key重复,多重就是允许key重复
2、有序关联容器
有序关联容器 => 底层是 红黑树 增删查O(log2n), 2是底数(树的层数,树的高度)
set
multiset
map
multimap

3、无序关联容器set的使用方式
unordered_set
unordered_set<int> set1;//不会存储key值重复的元素
for (int i = 0; i < 50; ++i)
{
set1.insert(rand()%20+1);//只需要给出值就可以了
//vector/deque/list insert(it, val)
}
cout << set1.size() << endl;//返回容器的元素的个数
cout << set1.count(15) << endl;//返回key为15的元素的个数
关联容器插入的时候(哈希表插入由哈希函数决定,红黑树是有自己的插入方法 )不用传位置参数(迭代器),只需要给出元素的值就可以了。

我们看到输出的结果:
- 元素的个数是18,说明插入的时候有很多元素的值是重复的相等的;
- 15这个元素出现了1次。这就是单重集合,插入时不允许key值重复。
unordered_multiset
我们换成多重集合unordered_multiset来看看:
unordered_multiset<int> set1;//不会存储key值重复的元素
for (int i = 0; i < 50; ++i)
{
set1.insert(rand()%20+1);//只需要给出值就可以了
//vector/deque/list insert(it, val)
}
cout << set1.size() << endl;//返回容器的元素的个数
cout << set1.count(15) << endl;//返回key为15的元素的个数

多重集合,允许key值重复,插入几个元素,它就存储几个。
遍历:
auto it1 = set1.begin();
for (; it1 != set1.end(); ++it1)
{
cout << *it1 << " ";
}
cout << endl;
删除操作:
erase可以接收key值或者迭代器
//删除一次
set1.erase(20);//按key值删除元素
//连续删除
for (it1 = set1.begin(); it1 != set1.end(); )//迭代器遍历
{
if (*it1 == 30)
{
it1 = set1.erase(it1);//调用erase,it1迭代器就失效了
}
else
{
++it1;//没有删除,要往下再走1步
}
}
find方法:
it1 = set1.find(20);
//存在的话返回指向这个元素的迭代器,不存在的话返回末尾迭代器
if (it1 != set1.end())
{
set1.erase(it1);//找到了,删除掉
}
for (int v : set1)//遍历
{
cout << v << " ";
}
cout << endl;
4、无序关联容器map的使用方式
map存储的是[key, value]键值对
map存储的是pair对象
struct pair
{
first; = > 表示的是key
second; = > 表示的是value
}
unordered_map
unordered_map使用代码:
unordered_map<int, string> map1;
map1.insert(make_pair(1000, "张三"));
map1.insert({ 1010, "李四" });//map表增加元素
map1.insert({ 1020, "王五" });
map1.insert({ 1030, "王凯" });
map1.erase(1020); //{1020, "王五" }删除了
cout << map1.size() << endl;//键值对的个数

auto it1 = map1.find(1030);
if (it1 != map1.end())
{
//it1 -> 打包成pair对象
cout << "key:" << it1->first << " value:" << it1->second << endl;
}
单重映射表不允许键重复!
unordered_multimap
多重映射表允许键重复


map的operator[]的功能:
1、查询的功能
2、如果key不存在,它会插入一对数据[key, string()](如果key不存在,它会把key,然后默认构造一个实例对象,组成键值对插入。)
V& operator[](const K& key)
{
insert({ key, V() });
}


键值对变成4对了!
map1[2000];//插入功能,key:2000 value:""
map1[2000] = "刘硕";//插入功能,map1.insert({2000, "刘硕"});
map1[1000] = "张三2";//修改功能
5、有序关联容器的使用方式

底层是红黑树。
set<int> set1;
for (int i = 0; i < 20; ++i)
{
set1.insert(rand() % 20 + 1);
}
for (int v : set1)
{
cout << v << " ";
}
cout << endl;

因为set是单重有序集合,所以默认按升序打印出来(就是通过中序遍历把红黑树访问了1遍),而且插入的key值不能重复。
set如果是存放自定义的类型:
需要提供 " < "运算符重载函数

按照key值从小到大排序的。

#include <iostream>
using namespace std;
#include <set>
#include <map>
class Student
{
public:
Student(int id, string name)
:_id(id), _name(name) {}
bool operator<(const Student& stu)const
{
return _id < stu._id;
}
private:
int _id;
string _name;
friend ostream& operator<<(ostream& out, const Student& stu);
};
ostream& operator<<(ostream& out, const Student& stu)
{
out << "id:" << stu._id << " name:" << stu._name << endl;
return out;
}
int main()
{
set<Student> set1;
set1.insert(Student(1020, "李广"));
set1.insert(Student(1000, "张雯"));
for (auto it = set1.begin();
it != set1.end(); ++it)
{
cout << *it << endl;
}
return 0;
}
map如果是存放自定义的类型:
map表需要Student提供默认构造函数,Student(int id = 0, string name = “”),为什么提供?
- 因为:stuMap[2000]-----》如果key不存在,就会构建 [2000, V()]键值对插入map表中 ,需要默认参数!
#include <iostream>
using namespace std;
#include <set>
#include <map>
class Student
{
public:
Student(int id = 0, string name = "")
:_id(id), _name(name) {}
private:
int _id;
string _name;
friend ostream& operator<<(ostream& out, const Student& stu);
};
ostream& operator<<(ostream& out, const Student& stu)
{
out << "id:" << stu._id << " name:" << stu._name << endl;
return out;
}
int main()
{
map<int, Student> stuMap; //map表需要Student提供默认构造函数,Student(int id = 0, string name = "")
stuMap.insert({ 1000, Student(1000, "张雯") });
stuMap.insert({ 1020, Student(1020, "李广") });
stuMap.insert({ 1030, Student(1030, "高洋") });
//删除的方法:stuMap.erase(it) stuMap.erase(1020)
//查询的方法:cout << stuMap[1020] << endl; stuMap.find(key)
//stuMap[2000]-----》如果key不存在,就会构建 [2000, V()]键值对插入map表中
//这里的key是整数,编译器知道如何给这个key进行排序
auto it = stuMap.begin();
for (; it != stuMap.end(); ++it)
{
cout << "key:" << it->first << " value:" << it->second << endl;
}
cout << endl;
return 0;
}
本文详细介绍了C++中的关联容器,包括无序关联容器和有序关联容器。无序关联容器如unordered_set、unordered_map采用哈希表,插入、查找和删除操作的时间复杂度为O(1)。有序关联容器如set、map则基于红黑树,操作时间复杂度为O(log2n)。文章通过实例展示了各种容器的插入、遍历、删除和查找方法,并讨论了自定义类型的键值对存储要求。
642

被折叠的 条评论
为什么被折叠?



