什么是有序关联容器
(1)顺序容器,容器中的元素是按它们在容器中的位置来顺序保存和访问的(可以理解是数组)
(2)顺序容器有array、vector、deque、list、forward_list、string等
(3)关联容器中的元素是按关键字来保存和访问的,关联的意思就是关键字(key)与存储值(value)的关联
(4)主要的关联容器类型是map和set
(5)关联容器支持高效的关键字查找和访问
(6)有序关联容器:容器内元素按顺序排列,一般用树(譬如红黑树)来实现
(7)无序关联容器:容器内元素无顺序排列,一般用哈希表来实现,本质上是一种映射
set的基本使用
(1)set的基本理解:就是一个用来装Key类型对象的筐子,数学上叫集合
(2)set的构造函数
(3)插入数据可以用insert,插入时内部自动排序,元素是唯一的
(4)查询set中元素个数用:empty、size,max_size是理论上的最大元素数
(5)清除全部元素用clear
(6)针对清除某个Key用erase,若erase的元素不存在则不报错
set的三种遍历方法
(1)使用ranged for
#include <iostream>
#include <set>
int main() {
std::set<int> mySet = {1, 2, 3, 4, 5};
for (int elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
(2)使用迭代器写for循环
```c
#include <iostream>
#include <set>
int main() {
std::set<int> mySet = {1, 2, 3, 4, 5};
// 使用范围for循环遍历
for (int elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
(3)使用std::for_each
```c
#include <iostream>
#include <set>
#include <algorithm>
void printElement(int elem) {
std::cout << elem << " ";
}
int main() {
std::set<int> mySet = {1, 2, 3, 4, 5};
// 使用std::for_each遍历
std::for_each(mySet.begin(), mySet.end(), printElement);
std::cout << std::endl;
return 0;
}
谓词可以是函数对象、函数、lambda表达式
set的原地构造
(1)set插入新元素一共有3个方法:insert、emplace、emplace_hint
(2)一般来说,emplace比insert效率更高,参考:http://c.biancheng.net/view/6834.html
移动构造
移动构造函数
(1)移动构造函数特征:传参是一个右值引用的对象(对比copy构造函数)
(2)右值引用的特征就是&&,
(3)右值引用对应移动语义,对应移动构造函数;而左值引用对应复制语义,对应复制构造函数
(4)移动语义就是直接把右值的临时对象给左值,而不是复制右值给左值重新构造一份
(5)移动构造函数可以避免不必要的深拷贝,这在很多时候可以提升效率
(6)此处案例,如果不提供移动构造函数,则会退而匹配调用拷贝构造函数,但不影响insert和emplace的对比
extract
std::set 引入了 extract 方法,该方法允许从 std::set 中移除一个元素,并返回一个包含该元素的 std::optional<std::set::node_type>。这个node_type 是一个指向 std::set 内部节点的指针,允许你以非破坏性的方式处理这个元素(例如,检查其内容或重新插入到另一个容器中)。如果容器为空或找不到元素,extract 将返回一个空的 std::optional。
#include <set>
#include <optional>
#include <iostream>
int main() {
std::set<int> s = {1, 2, 3, 4, 5};
auto extracted = s.extract(3);
if (extracted) {
std::cout << "Extracted: " << extracted->value() << std::endl;
// 可以选择性地重新插入到另一个集合
// std::set<int> s2;
// s2.insert(std::move(extracted.value()));
// extracted = std::nullopt; // 必须显式重置extracted,因为node的所有权已转移
}
// s现在不再包含3
for (int x : s) {
std::cout << x << ' ';
}
std::cout << std::endl;
return 0;
}
#include <iostream>
#include <set>
int main() {
// 创建一个空的set
std::set<int> mySet;
// 插入元素
mySet.insert(10);
mySet.insert(5);
mySet.insert(15);
mySet.insert(20);
// 遍历set(注意:set会自动排序)
std::cout << "遍历set(已排序):" << std::endl;
for (int elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 查找元素
auto it = mySet.find(15);
if (it != mySet.end()) {
std::cout << "找到元素:" << *it << std::endl;
} else {
std::cout << "未找到元素" << std::endl;
}
// 删除元素
size_t num_erased = mySet.erase(10);
if (num_erased) {
std::cout << "删除元素10成功" << std::endl;
}
// 再次遍历set以查看删除效果
std::cout << "删除元素后再次遍历set:" << std::endl;
for (int elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 获取set的大小
std::cout << "set的大小为:" << mySet.size() << std::endl;
// 清空set
mySet.clear();
// 检查set是否为空
if (mySet.empty()) {
std::cout << "set已清空" << std::endl;
}
return 0;
}