目录
1、set
std::set 是 C++ 标准模板库(STL)中的一个关联容器,用于存储唯一元素,并按照某种排序规则自动排序(默认是 <
运算符)。它通常基于红黑树(一种自平衡二叉搜索树)实现(红黑树通过颜色标记和旋转操作保持树的平衡,确保插入、删除和查找操作的时间复杂度为 O(logn))
struct Node {
T value; // 数据域
Node* left; // 左子节点
Node* right; // 右子节点
Node* parent; // 父节点
bool color; // 颜色标记(红或黑)
};
std::set 的迭代器是一个双向迭代器,支持 ++ 和 -- 操作。
迭代器的实现通常是对红黑树节点的封装
构造函数
set(): 默认构造函数创建一个空的 set | set(const set& other): 拷贝构造函数 |
set(initializer_list<T> init): 使用初始化列表创建 set |
元素访问
begin(), end(): 返回指向第一个元素和最后一个元素之后位置的迭代器 | |
rbegin(), rend(): 返回反向迭代器 | cbegin(), cend(), crbegin(), crend(): 返回常量迭代器 |
std::set 的迭代器是一个双向迭代器,支持 ++ 和 -- 操作。迭代器的实现通常是对红黑树节点的封装。erase:删除元素时指向被删除元素的迭代器失效。insert:插入元素不会使其他迭代器失效
容量
empty(): 判空。size(): 返回 set 中的元素数量。max_size(): 返回 set 可以容纳的最大元素数量。
修改
clear(): 清除 set 中的所有元素 | insert(const T& value): 插入元素 value |
erase(iterator pos): 删除指定位置 pos 处的元素 | erase(const T& value): 删除值为 value 的元素 |
swap(set& other): 交换两个 set 的内容 |
查找
find(const T& value): 返回指向值为 value 的元素的迭代器,如果未找到则返回 end() |
count(const T& value): 返回值为 value 的元素的数量(对于 set,结果为 0 或 1) |
lower_bound(const T& value): 返回指向第一个不小于 value 的元素的迭代器 |
upper_bound(const T& value): 返回指向第一个大于 value 的元素的迭代器 |
equal_range(const T& value): 返回一个包含 lower_bound 和 upper_bound 的 pair |
code实例
#include <set>
#include <iostream>
int main() {
//初始化
std::set<int> s1; // 空 set
std::set<int> s = {3, 1, 4, 1, 5}; // 使用初始化列表创建 set(重复元素会被忽略)
//容量
std::cout << "s.empty(): " << s.empty() << std::endl; // 输出: 0 (false)
std::cout << "s.size(): " << s.size() << std::endl; // 输出: 4
std::cout << "s.max_size(): " << s.max_size() << std::endl; // 输出: 一个很大的数
//修改
s.insert(2); // s: {1, 2, 3, 4, 5}
//s.erase(4); // s: {1, 2, 3, 5}
//s.erase(s.begin()); // s: {2, 3, 5}
auto it = s.find(3);
if (it != s.end()) {
std::cout << "Found: " << *it << std::endl; // 输出: Found: 3
}
std::cout << "s.count(2): " << s.count(2) << std::endl; // 输出: 1
std::cout << "s.count(6): " << s.count(6) << std::endl; // 输出: 0
auto lb = s.lower_bound(3);
auto ub = s.upper_bound(3);
std::cout << "Lower bound of 3: " << *lb << std::endl; // 输出: 3
std::cout << "Upper bound of 3: " << *ub << std::endl; // 输出: 4
auto range = s.equal_range(3);
// 检查是否有找到等于value的元素
if (range.first != range.second) {
std::cout << "range begin: " << *range.first << std::endl; //3
std::cout << "range end: " << *(range.second) << std::endl; //4 注:如果要获取范围的最后一个元素,需要用--操作符
} else {
std::cout << "no." << std::endl;
}
//迭代器
for (auto ite = s.begin(); ite != s.end();) {
if (*ite % 2 == 0) {
ite = s.erase(ite); // 删除偶数元素
} else {
++ite;
}
//for里不加++, 当 erase 删除一个元素后,erase 会返回指向下一个元素的迭代器。
//如果for里有++,你在删除元素后仍然执行了++ite,这会导致迭代器跳过某些元素,甚至进入死循环。
}
for (auto it = s.rbegin(); it != s.rend(); ++it) {
std::cout << *it << " "; // 输出: 5 3 1
}
return 0;
}
实现简单的set
#include <iostream>
#include <memory>
enum Color { RED, BLACK };
template <typename T>
struct Node {
T value;
Color color;
std::shared_ptr<Node<T>> left, right, parent;
Node(T val) : value(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};
template <typename T>
class SimpleSet {
private:
std::shared_ptr<Node<T>> root;
void rotateLeft(std::shared_ptr<Node<T>> node);
void rotateRight(std::shared_ptr<Node<T>> node);
void fixInsert(std::shared_ptr<Node<T>> node);
void insert(std::shared_ptr<Node<T>> node, T value);
std::shared_ptr<Node<T>> find(std::shared_ptr<Node<T>> node, T value) const;
public:
SimpleSet() : root(nullptr) {}
void insert(T value);
bool contains(T value) const;
};
template <typename T>
void SimpleSet<T>::insert(T value) {
if (!root) {
root = std::make_shared<Node<T>>(value);
root->color = BLACK;
} else {
insert(root, value);
}
}
template <typename T>
bool SimpleSet<T>::contains(T value) const {
return find(root, value) != nullptr;
}
// 其他方法(旋转、修复插入等)需要进一步实现
int main() {
SimpleSet<int> s;
s.insert(3);
s.insert(1);
s.insert(4);
std::cout << "Contains 1: " << s.contains(1) << std::endl; // 输出: 1 (true)
std::cout << "Contains 2: " << s.contains(2) << std::endl; // 输出: 0 (false)
return 0;
}
2、std::multiset
std::multiset 关联容器,用于存储元素并按照某种排序规则自动排序。与std::set 不同std::multiset允许存储重复的元素。它通常基于红黑树(一种自平衡二叉搜索树)实现。特点:自平衡:红黑树通过颜色标记和旋转操作保持树的平衡,确保插入、删除和查找操作的时间复杂度为 O(logn)。元素按照严格的弱序(默认是 < 运算符)排序。允许重复:std::multiset 中的元素可以重复。
struct Node {
T value; // 数据域
Node* left; // 左子节点
Node* right; // 右子节点
Node* parent; // 父节点
bool color; // 颜色标记(红或黑)
};
构造函数
multiset(): 默认构造函数,创建一个空的 multiset |
multiset(const multiset& other): 拷贝构造函数 |
multiset(initializer_list<T> init): 使用初始化列表创建 multiset |
元素访问
begin(), end(): 返回指向第一个元素和最后一个元素之后位置的迭代器 |
rbegin(), rend(): 返回反向迭代器 |
cbegin(), cend(), crbegin(), crend(): 返回常量迭代器 |
std::multiset 的迭代器是一个双向迭代器,支持 ++ 和 -- 操作。迭代器的实现通常是对红黑树节点的封装。erase:删除元素时,指向被删除元素的迭代器失效。insert:插入元素不会使其他迭代器失效
容量
empty(): 判空。 size(): 返回 multiset 中的元素数量。 max_size(): 返回 multiset 可以容纳的最大元素数量
修改器
clear(): 清除 multiset 中的所有元素 | insert(const T& value): 插入元素 value |
erase(iterator pos): 删除指定位置 pos 处的元素 | swap(multiset& other): 交换两个 multiset 的内容 |
erase(const T& value): 删除所有值为 value 的元素 |
查找操作
count(const T& value): 返回值为 value 的元素的数量 |
find(const T& value): 返回指向第一个值为 value 的元素的迭代器,如果未找到则返回 end() |
lower_bound(const T& value): 返回指向第一个不小于 value 的元素的迭代器 |
upper_bound(const T& value): 返回指向第一个大于 value 的元素的迭代器。 |
equal_range(const T& value): 返回一个包含 lower_bound 和 upper_bound 的 pair |
code举例
#include <iostream>
#include <set>
int main() {
//构造函数
std::multiset<int> ms1; // 空 multiset
std::multiset<int> ms = {3, 1, 4, 1, 5}; // 使用初始化列表创建 multiset(允许重复元素)
//容量
std::cout << "ms.empty(): " << ms.empty() << std::endl; // 输出: 0 (false)
std::cout << "ms.size(): " << ms.size() << std::endl; // 输出: 5
std::cout << "ms.max_size(): " << ms.max_size() << std::endl; // 输出: 一个很大的数
//修改
ms.insert(2); // ms: {1, 1, 2, 3, 4, 5}
ms.erase(1); // ms: {2, 3, 4, 5}
ms.clear();
std::multiset<int> mst = {3, 1, 4, 1, 5};
swap(ms,mst);
//查找
auto it = ms.find(3);
if (it != ms.end()) {
std::cout << "Found: " << *it << std::endl; // 输出: Found: 3
}
std::cout << "ms.count(1): " << ms.count(1) << std::endl; // 输出: 2
std::cout << "ms.count(6): " << ms.count(6) << std::endl; // 输出: 0
auto lb = ms.lower_bound(3);
auto ub = ms.upper_bound(3);
std::cout << "Lower bound of 3: " << *lb << std::endl; // 输出: 3
std::cout << "Upper bound of 3: " << *ub << std::endl; // 输出: 4
auto range = ms.equal_range(3);
if (range.first != range.second) {
std::cout << "Range begin: " << *range.first << std::endl; // 输出: 3
std::cout << "Range end: " << *range.second << std::endl; // 输出: 4
} else {
std::cout << "No range found." << std::endl;
}
//迭代器
for (auto it = ms.begin(); it != ms.end(); ++it) {
std::cout << *it << " "; // 输出: 1 1 3 4 5
}
return 0;
}
实现简单的
#include <iostream>
#include <memory>
enum Color { RED, BLACK };
template <typename T>
struct Node {
T value;
Color color;
std::shared_ptr<Node<T>> left, right, parent;
Node(T val) : value(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};
template <typename T>
class SimpleMultiset {
private:
std::shared_ptr<Node<T>> root;
void rotateLeft(std::shared_ptr<Node<T>> node);
void rotateRight(std::shared_ptr<Node<T>> node);
void fixInsert(std::shared_ptr<Node<T>> node);
void insert(std::shared_ptr<Node<T>> node, T value);
std::shared_ptr<Node<T>> find(std::shared_ptr<Node<T>> node, T value) const;
public:
SimpleMultiset() : root(nullptr) {}
void insert(T value);
bool contains(T value) const;
};
template <typename T>
void SimpleMultiset<T>::insert(T value) {
if (!root) {
root = std::make_shared<Node<T>>(value);
root->color = BLACK;
} else {
insert(root, value);
}
}
template <typename T>
bool SimpleMultiset<T>::contains(T value) const {
return find(root, value) != nullptr;
}
// 其他方法(旋转、修复插入等)需要进一步实现
int main() {
SimpleMultiset<int> ms;
ms.insert(3);
ms.insert(1);
ms.insert(4);
ms.insert(1);
std::cout << "Contains 1: " << ms.contains(1) << std::endl; // 输出: 1 (true)
std::cout << "Contains 2: " << ms.contains(2) << std::endl; // 输出: 0 (false)
return 0;
}
3、std::map
std::map 的底层实现通常是一个红黑树(Red-Black Tree),自平衡:红黑树通过颜色标记和旋转操作保持树的平衡,确保插入、删除和查找操作的时间复杂度为 O(logn)。排序:键按照严格的弱序(默认是 < 运算符)排序。唯一性:std::map 中的键是唯一的,不允许重复。
struct Node {
std::pair<const Key, T> value; // 键值对
Node* left; // 左子节点
Node* right; // 右子节点
Node* parent; // 父节点
bool color; // 颜色标记(红或黑)
};
构造函数
map(): 默认构造函数,创建一个空的 map | map(const map& other): 拷贝构造函数 |
map(initializer_list<std::pair<const Key, T>> init): 使用初始化列表创建 map |
元素访问
operator[](const Key& key): 返回键为 key 的值的引用,如果键不存在则插入一个默认值 | |
at(const Key& key): 返回键为 key 的值的引用,如果键不存在则抛出 std::out_of_range 异常 |
容量操作
empty(): 判空。size(): 返回 map 中的键值对数量。max_size(): 返回 map 可以容纳的最大键值对数量。
修改
clear() | 清除所有元素 |
insert() | 插入元素或节点(C++17 起) |
insert_range() | 插入元素范围 |
insert_or_assign() | (C++17) 插入元素,或若键已存在则赋值给当前元素 |
emplace() | (C++11)原位构造元素 |
emplace_hint() | (C++11)使用提示原位构造元素 |
try_emplace() | (C++17)若键不存在则原位插入,若键存在则不做任何事 |
erase() | 擦除元素 |
swap() | 交换两个 std::map 的内容 |
extract() | (C++17)提取容器中的节点 |
merge() | (C++17)从另一容器合并节点 |
查找
count()返回匹配特定键的元素数量 | find()寻找带有特定键的元素 |
equal_range()返回匹配特定键的元素范围 | contains() (C++20)检查容器是否含有带特定键的元素 |
lower_bound()返回指向首个不小于给定键的元素的迭代器 | |
upper_bound()返回指向首个大于给定键的元素的迭代器 |
code实例
#include <iostream>
#include <map>
#include <string>
int main() {
//构造
std::map<int, std::string> m1; // 空 map
std::map<int, std::string> m = {{1, "one"}, {2, "two"}, {3, "three"}}; // 使用初始化列表创建 map
//元素访问
std::cout << "m[2]: " << m[2] << std::endl; // 输出: two
std::cout << "m.at(3): " << m.at(3) << std::endl; // 输出: three
//容量
std::cout << "m.empty(): " << m.empty() << std::endl; // 输出: 0 (false)
std::cout << "m.size(): " << m.size() << std::endl; // 输出: 3
std::cout << "m.max_size(): " << m.max_size() << std::endl; // 输出: 一个很大的数
// 1. clear: 清除内容
std::cout << "Before clear, size: " << m.size() << std::endl; // 输出: 3
m.clear();
std::cout << "After clear, size: " << m.size() << std::endl; // 输出: 0
// 2. insert: 插入元素或节点
m.insert({4, "four"}); // 插入单个键值对
m.insert(std::make_pair(5, "five")); // 插入 pair
// 3. insert_range (C++23): 插入元素范围
std::map<int, std::string> m2 = {{6, "six"}, {7, "seven"}};
m.insert(m2.begin(), m2.end()); // 插入范围
// 4. insert_or_assign (C++17): 插入元素,或若键已存在则赋值
m.insert_or_assign(3, "THREE"); // 键 3 已存在,更新值
m.insert_or_assign(8, "eight"); // 键 8 不存在,插入新键值对
// 5. emplace (C++11): 原位构造元素
m.emplace(9, "nine"); // 直接构造键值对
// 6. emplace_hint (C++11): 使用提示原位构造元素
auto hint = m.find(9); // 获取一个迭代器作为提示
m.emplace_hint(hint, 10, "ten"); // 在提示位置插入
// 7. try_emplace (C++17): 若键不存在则原位插入,若键存在则不做任何事
m.try_emplace(10, "TEN"); // 键 10 已存在,不做任何事
m.try_emplace(11, "eleven"); // 键 11 不存在,插入新键值对
// 8. erase: 擦除元素
m.erase(11); // 删除键为 11 的键值对
auto it = m.find(10);
if (it != m.end()) {
m.erase(it); // 通过迭代器删除
}
// 9. swap: 交换内容
std::map<int, std::string> m3 = {{12, "twelve"}, {13, "thirteen"}};
m.swap(m3); // 交换 m 和 m3 的内容
// 10. extract (C++17): 提取容器中的节点
auto node = m.extract(12); // 提取键为 12 的节点
if (!node.empty()) {
std::cout << "Extracted node: " << node.key() << ": " << node.mapped() << std::endl; // 输出: Extracted node: 12: twelve
}
// 11. merge (C++17): 从另一容器合并节点
std::map<int, std::string> m4 = {{14, "fourteen"}, {15, "fifteen"}};
m.merge(m4); // 将 m4 中的节点合并到 m
// ------------------------- 查找 -------------------------
// 12. count: 返回匹配特定键的元素数量
std::cout << "Count of key 14: " << m.count(14) << std::endl; // 输出: 1
// 13. find: 寻找带有特定键的元素
auto find_it = m.find(15);
if (find_it != m.end()) {
std::cout << "Found: " << find_it->first << ": " << find_it->second << std::endl; // 输出: Found: 15: fifteen
}
// 14. equal_range: 返回匹配特定键的元素范围
auto range = m.equal_range(14);
for (auto it = range.first; it != range.second; ++it) {
std::cout << "Equal range: " << it->first << ": " << it->second << std::endl; // 输出: Equal range: 14: fourteen
}
// 15. lower_bound: 返回指向首个不小于给定键的元素的迭代器
auto lb = m.lower_bound(13);
if (lb != m.end()) {
std::cout << "Lower bound of 13: " << lb->first << ": " << lb->second << std::endl; // 输出: Lower bound of 13: 14: fourteen
}
// 16. upper_bound: 返回指向首个大于给定键的元素的迭代器
auto ub = m.upper_bound(14);
if (ub != m.end()) {
std::cout << "Upper bound of 14: " << ub->first << ": " << ub->second << std::endl; // 输出: Upper bound of 14: 15: fifteen
}
// ------------------------- 观察器 -------------------------
// 17. key_comp: 返回用于比较键的函数
auto key_compare = m.key_comp();
std::cout << "Compare keys 14 and 15: " << key_compare(14, 15) << std::endl; // 输出: 1 (true, 14 < 15)
// 18. value_comp: 返回用于比较 value_type 类型的对象中的键的函数
auto value_compare = m.value_comp();
auto val1 = *m.find(14);
auto val2 = *m.find(15);
std::cout << "Compare values (14, fourteen) and (15, fifteen): " << value_compare(val1, val2) << std::endl; // 输出: 1 (true, 14 < 15)
// 输出最终的 map 内容
std::cout << "Final map contents:" << std::endl;
for (const auto& pair : m) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}
实现简单的std::map
#include <iostream>
#include <memory>
enum Color { RED, BLACK };
template <typename Key, typename T>
struct Node {
std::pair<const Key, T> value;
Color color;
std::shared_ptr<Node<Key, T>> left, right, parent;
Node(const std::pair<const Key, T>& val) : value(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};
template <typename Key, typename T>
class SimpleMap {
private:
std::shared_ptr<Node<Key, T>> root;
void rotateLeft(std::shared_ptr<Node<Key, T>> node);
void rotateRight(std::shared_ptr<Node<Key, T>> node);
void fixInsert(std::shared_ptr<Node<Key, T>> node);
void insert(std::shared_ptr<Node<Key, T>> node, const std::pair<const Key, T>& value);
std::shared_ptr<Node<Key, T>> find(std::shared_ptr<Node<Key, T>> node, const Key& key) const;
public:
SimpleMap() : root(nullptr) {}
void insert(const std::pair<const Key, T>& value);
bool contains(const Key& key) const;
};
template <typename Key, typename T>
void SimpleMap<Key, T>::insert(const std::pair<const Key, T>& value) {
if (!root) {
root = std::make_shared<Node<Key, T>>(value);
root->color = BLACK;
} else {
insert(root, value);
}
}
template <typename Key, typename T>
bool SimpleMap<Key, T>::contains(const Key& key) const {
return find(root, key) != nullptr;
}
// 其他方法(旋转、修复插入等)需要进一步实现
int main() {
SimpleMap<int, std::string> m;
m.insert({1, "one"});
m.insert({2, "two"});
m.insert({3, "three"});
std::cout << "Contains 2: " << m.contains(2) << std::endl; // 输出: 1 (true)
std::cout << "Contains 4: " << m.contains(4) << std::endl; // 输出: 0 (false)
return 0;
}
4、std::multimap
std::multimap 是 C++ 标准模板库(STL)中的一个关联容器,用于存储键值对(key-value pairs),并按照键的顺序自动排序。与 std::map 不同,std::multimap 允许存储重复的键
int main() {
// 构造函数
std::multimap<int, std::string> mm1; // 1. 默认构造函数:创建一个空的 multimap
std::multimap<int, std::string> mm2 = {{1, "one"}, {2, "two"}, {2, "TWO"}};
// 1: one 2: two 2: TWO
std::multimap<int, std::string> mm3(mm2);// 拷贝构造函数
// 元素访问
for (auto it = mm2.begin(); it != mm2.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
// 输出: 1: one 2: two 2: TWO
for (auto rit = mm2.rbegin(); rit != mm2.rend(); ++rit) {
std::cout << rit->first << ": " << rit->second << std::endl;
}
// TWO 2: two 1: one
//容量
std::cout << "mm1 is empty: " << mm1.empty() << std::endl; // 输出: 1 (true)
std::cout << "mm2 is empty: " << mm2.empty() << std::endl; // 输出: 0 (false)
std::cout << "mm2 size: " << mm2.size() << std::endl; // 输出: 3
std::cout << "mm2 max_size: " << mm2.max_size() << std::endl; // 输出: 一个很大的数
// 修改
mm2.insert({3, "three"});
mm2.insert({2, "TWO-2"}); // 允许重复键
mm2.erase(2); // 删除所有键为 2 的键值对
std::cout << "After erase, mm2 contents:" << std::endl;
for (const auto& pair : mm2) {
std::cout << pair.first << ": " << pair.second << std::endl;
}// 1: one 3: three
mm2.clear();
std::cout << "After clear, mm2 size: " << mm2.size() << std::endl; // 输出: 0
std::multimap<int, std::string> mm4 = {{4, "four"}, {5, "five"}};
mm2.swap(mm4);
std::cout << "After swap, mm2 contents:" << std::endl;
for (const auto& pair : mm2) {
std::cout << pair.first << ": " << pair.second << std::endl;
}// 4: four 5: five
// 查找操作
auto it = mm2.find(4);
if (it != mm2.end()) {
std::cout << "Found: " << it->first << ": " << it->second << std::endl; // 输出: Found: 4: four
}
std::cout << "Count of key 5: " << mm2.count(5) << std::endl; // 输出: 1
auto lb = mm2.lower_bound(4);
auto ub = mm2.upper_bound(4);
std::cout << "Lower bound of 4: " << lb->first << ": " << lb->second << std::endl; // 输出: 4: four
std::cout << "Upper bound of 4: " << ub->first << ": " << ub->second << std::endl; // 输出: 5: five
auto range = mm2.equal_range(4);
for (auto it = range.first; it != range.second; ++it) {
std::cout << "Equal range: " << it->first << ": " << it->second << std::endl; // 输出: 4: four
}
return 0;
}