关联式容器
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是'<'key, value'>'结构的键值对,在数据检索时比序列式容器效率更高。
STL中的部分容器,比如:vector、list、deque、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。
STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的底层实现是使用平衡搜索树(即红黑树),并且容器中的元素是一个有序的序列。
set
#include
set特点
1.key和value都能唯一标识元素
2.set中的元素不可以重复(因此可以使用set去重)
3.set中的元素不能在容器中修改,只能删除和插入
4.set容器通过key访问单个元素的速度通常比unordered_set容器慢,set不能通过[key]访问值,set没有重载[]运算符
5.与map/multimap不同,map/multimap中存储的是真正的键值对<key,value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
set用法
#include
set定义及初始化
1.用初始化列表来初始化 set 容器:
set<int> se = {1, 7, 5, 6, 9, 3, 4, 0, 2};
set<int, greater<int>> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 }; //加greater<int>后set降序
2.用集合初始化集合
set<int> a; // 定义一个int类型的集合a
set<int> b(a); // 定义并用集合a初始化集合b
set<int> b(a.begin(), a.end()); // 将集合a中的所有元素作为集合b的初始值
3.list a(n, n + x); // 将数组n的前x个元素作为集合a的初值
int array[] = { 1, 3, 5, 7, 9, 2};
set<int> s(array, array+sizeof(array)/sizeof(array));
插入
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
se.insert(7); //插入失败,set中的元素不可以重复(其实因为set元素的键值对key和value值相同, 如果完全相同的元素重复没有任何意义,而且会造成数据冗余)
se.insert(8); //插入成功
删除
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
//删除指定值得元素, 返回值是删除值为x的元素的个数
se.erase(7);
//删除迭代器所迭代的元素
set<int>::iterator pos = find(se.begin(), se.end(), 5);
se.erase(pos);
//删除迭代器区间上的元素, 左闭右开[pos1, pos2)
set<int>::iterator pos1 = find(se.begin(), se.end(), 1);
set<int>::iterator pos2 = find(se.begin(), se.end(), 4);
se.erase(pos1, pos2);
求容量及判空
//求容量
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
cout << se.size() << endl;
//判空
set<int> se1;
cout << se.empty() << endl; //返回值0 非空
cout << se1.empty() << endl; //返回值1 空
清空
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
se.clear();
cout << se.empty() << endl;
交换
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
set<int> se2 = {8, 9, 11, 15, 32, 64, 128};
cout << se.size() << endl;
se2.swap(se);
for (const auto& e : se)
cout << e << " ";
cout << endl;
//se: 8 9 11 15 32 64 128
for (const auto& e : se2)
cout << e << " ";
cout << endl;
//se2: 0 1 2 3 4 5 6 7 9
遍历
1.利用C++ auto
(1).不加const
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
for (auto& e : se)
cout << e << " ";
cout << endl;
由于set不允许修改元素,因此无论是否是反向迭代器或者常迭代器,都不能修改set
(1).加const
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
for (const auto& e : se)
cout << e << " ";
cout << endl;
auto关键字遍历的话,如果给auto关键字前面加上const,for (const auto e : people) 那么就无法通过e来修改值了
2.利用迭代器
(1).正向迭代器
map<string, size_t>::iterator
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
set<int>::iterator it = se.begin(); //或者: auto it = se.begin();
while(it != se.end())
{
cout<<*it<<" ";
++it;
}
(2).正向常迭代器
map<string, size_t>::const_iterator
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
set<int>::const_iterator it = se.cbegin(); //或者: auto it = se.begin();
while (it != se.cend())
{
cout << *it << " ";
++it;
}
(3).反向迭代器
map<string, size_t>::reverse_iterator
set<int>::reverse_iterator it = se.rbegin(); //或者: auto it = se.begin();
while (it != se.rend())
{
cout << *it << " ";
++it;
}
(4).反向常迭代器
map<string, size_t>::const_reverse_iterator
set<int>::const_reverse_iterator it = se.crbegin(); //或者: auto it = se.begin();
while (it != se.crend())
{
cout << *it << " ";
++it;
}
查找 时间复杂度为:
log_2 n
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
set<int>::iterator pos = find(se.begin(), se.end(), 5);
multiset
#include
multiset特点(与set的区别是)
1.multiset中的元素可以重复,set是中value是唯一的
multiset<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
se.insert(7);
multiset<int>::iterator it = se.begin();
while (it != se.end())
cout << *it++;
cout << endl;
//输出: 0123456779
2.multiset容器通过key访问单个元素的速度通常比比unordered_multiset容器慢
multiset用法与set相似
插入 容量及判空 清空 交换相似
删除与set不同:
删除指定值的元素, 返回值是删除值为x的元素的个数
multiset<int> multise = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
multise.insert(7);
int erasenum = multise.erase(7); //返回删除值为x的元素的个数
cout << "erase(7)"<< erasenum <<"个"<<endl;
与set查找不同:
multiset<int> multise = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
multiset<int>::iterator mulit = multise.find(7);
unordered_set
#include<unordered_set>
unordered_set特点
1.无序
int arr[] = {5, 4, 3, 1, 7, 4, 9, 0};
unordered_set<int> unorderse(arr, arr+ sizeof(arr)/sizeof(int));
unordered_set<int>::iterator uorit = unorderse.begin();
while (uorit != unorderse.end())
cout << *uorit++;
cout << endl;
//输出:5439170
2.元素不重复
unorderse.insert(10);
unorderse.insert(10);
unorderse.erase(10);
while (uorit != unorderse.end())
cout << *uorit++;
cout << endl;
//out: 5439170
3.swap只能是相同set才能交换
int arr[] = {5, 4, 3, 1, 7, 4, 9, 0};
unordered_set<int> unorderse(arr, arr+ sizeof(arr)/sizeof(int));
set<int> se = { 1, 7, 5, 6, 9, 3, 4, 0, 2 };
unorderse.swap(se); //error
unordered_set用法与set相似
插入 删除 容量及判空 清空 交换相似
与set查找不同:
int arr[] = {5, 4, 3, 1, 7, 4, 9, 0};
unordered_set<int> unorderse(arr, arr+ sizeof(arr)/sizeof(int));
unordered_set<int>::iterator find = unorderse.find(10);
cout << *find << endl;
unordered_multiset
#include
unordered_multiset特点(与multiset的区别是)
1.可以插入值相同的元素,相同值的元素会放在一块
unordered_multiset<int> unmulset = {4, 6, 7, 8, 3, 4, 9, 10};
unordered_multiset<int>::iterator unorderedit = unmulset.begin();
while (unorderedit != unmulset.end())
cout << *unorderedit++;
cout << endl;
//out: 4467839105
unordered_multiset用法与multiset相似
插入 删除 容量及判空 清空 交换 查找相似