文章目录
set/multiset容器概念
set和multiset是一个集合容器,其中set所包含的元素是唯一的,集合中的元素按一定的顺序排列。set采用红黑树变体的数据结构实现,红黑树属于平衡二叉树。在插入操作和删除操作上比vector快。在n个数中查找目标数的效率是 log2 n
特点
set中元素插入过程是按排序规则插入,所以不能指定插入位置。
set不可以直接存取元素。(不可以使用at.(pos)与[]操作符)。
multiset与set的区别:set支持唯一键值,每个元素值只能出现一次;而multiset中同一值可以出现多次。
不可以直接修改set或multiset容器中的元素值,因为该类容器是自动排序的。如果希望修改一个元素值,必须先删除原有的元素,再插入新的元素
红黑树
红黑树定义 — 是每个节点都带有颜色属性(颜色为红色或黑色)的自平衡二叉查找树,满足下列性质:
1)节点是红色或黑色;
2)根节点是黑色;
3)所有叶子节点都是黑色节点(NULL);
4)每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
5)从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
set/multiset容器操作
set/multiset对象的默认构造
set<string> setString; //一个存放string的set容器。
multiset<int> mulsetInt; //一个存放int的multi set容器。
Set/multiset 对象的带参构造函数
set(beg,end); //将[beg, end)区间中的元素拷贝给本身。
set(const set &s); //拷贝构造函数。
multiset(beg,end); //将[beg, end)区间中的元素拷贝给本身。
multiset(const multiset &s); //拷贝构造函数。
set对象的拷贝构造与赋值
set(const set &st); //拷贝构造函数
set& operator=(const set &st); //重载等号操作符
set.swap(st); //交换两个集合容器
setIntA.insert(5);
set<int> setIntA;
setIntA.insert(1);
setIntA.insert(2);
setIntA.insert(3);
setIntA.insert(4);
set<int> setIntB(setIntA); //1 2 3 4 5
set<int> setIntC;
setIntC = setIntA; //1 2 3 4 5
setIntC.insert(6); //1 2 3 4 5 6
setIntC.swap(setIntA); //交换
set和pair用法
set/multiset的大小
set/multiset的删除
删除区间内的某个或某些元素
setInt是用set<int>声明的容器,假设它内部现已包含按顺序的1, 2, 3, 4, 5, 6元素。
set<int>::iterator itBegin=setInt.begin();
++ itBegin;
set<int>::iterator itEnd=setInt.begin();
++ itEnd;
++ itEnd;
++ itEnd;
setInt.erase(itBegin,itEnd);
//此时容器setInt包含按顺序的1, 4, 5, 6四个元素。
删除容器中第一个元素
setInt.erase(setInt.begin()); //4, 5, 6
删除容器中值为5的元素
setInt.erase(5); //4, 6
删除setInt的所有元素
setInt.clear(); //容器为空
set/multiset的查找
set.find(elem); //查找elem元素,返回指向elem元素的迭代器。
set.count(elem); //返回容器中值为elem的元素个数。对set来说,要么是0,要么是1。对multiset来说,值可能大于1。
set.lower_bound(elem); //返回第一个不小于elem元素的迭代器。
set.upper_bound(elem); // 返回第一个>elem元素的迭代器。
set.equal_range(elem); //返回容器中与elem相等的上下限的两个迭代器。上限是闭区间,下限是开区间,如[beg,end)。以上函数返回两个迭代器,而这两个迭代器被封装在pair中。
仿函数
仿函数(Function Object)在C++中是一种行为类似于函数的对象。它们通常通过重载操作符`()`来实现,
使得对象可以像函数一样被调用。类模板是C++模板编程的一部分,允许你定义一个类,它可以在多种数
据类型上复用。将仿函数和类模板结合起来,可以创建出灵活且可重用的函数对象。
定义仿函数类模板:
类模板可以定义为仿函数,通过重载operator()
来实现调用功能。template<typename T> class MyFunctor { public: T operator()(const T& x, const T& y) const { return x + y; // 例如,一个简单的加法仿函数 } };
使用仿函数类模板:
创建仿函数对象时,可以指定模板参数,从而使用不同的数据类型。MyFunctor<int> intAdder; // 用于整数的加法仿函数 MyFunctor<double> doubleAdder; // 用于双精度浮点数的加法仿函数
模板参数推断:
当使用仿函数时,编译器可以从上下文推断模板参数的类型。MyFunctor autoAdder(10, 20); // 编译器推断出autoAdder是MyFunctor<int>
重载操作符:
仿函数类模板通常重载operator()
,使其可以像函数一样被调用。auto result = intAdder(5, 3); // 调用仿函数,结果为8
仿函数与算法结合:
仿函数可以与标准库算法结合使用,为算法提供自定义的行为。#include <algorithm> #include <vector> std::vector<int> numbers = {1, 2, 3, 4, 5}; std::transform(numbers.begin(), numbers.end(), numbers.begin(), MyFunctor<int>());
仿函数作为模板参数:
仿函数类模板本身可以作为另一个模板的参数。template<typename Functor> class Algorithm { public: void apply(std::vector<typename Functor::argument_type>& vec) { std::for_each(vec.begin(), vec.end(), Functor()); } }; Algorithm<MyFunctor<int>> alg; alg.apply(numbers);
仿函数的灵活性:
仿函数可以捕获外部变量,具有状态,或者不捕获任何变量,具有无状态的特性。template<typename T> class StatefulFunctor { T state; public: StatefulFunctor(T s) : state(s) {} T operator()(const T& x) const { return x * state; // 使用状态进行计算 } };
仿函数与lambda表达式:
C++11及以后的版本支持lambda表达式,它们可以作为仿函数使用,提供更简洁的语法。auto lambdaAdder = [](int x, int y) { return x + y; };