STL关联式容器解析:map与set详解

目录

1. 关联式容器

2. 键值对

3. 树形结构的关联式容器

3.1 set

3.1.2 set的使用

3.2 map

3.2.1 map的介绍

3.2.2 map的使用

3.3 multiset

3.3.1 multiset的介绍

3.3.2 multiset的使用

3.4 multimap

3.4.1 multimap的介绍

3.4.2 multimap的使用

4.红黑树模拟实现STL中的map与set

4.1红黑树的节点定义

4.2 红黑树的迭代器

4.3改造红黑树

4.4 map的模拟实现

4.5 set的模拟实现


1. 关联式容器

在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、 forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面 存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?

  关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是结构的 键值对,在数据检索时比序列式容器效率更高。

2. 键值对

  用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代 表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然 有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应 该单词,在词典中就可以找到与其对应的中文含义。

3. 树形结构的关联式容器

  根据应用场景的不桶,STL总共实现了两种不同结构的关联式容器:树型结构与哈希结构。树型结 构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使 用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。下面一依次介绍每一 个容器。

3.1 set

3.1.1 set的介绍

1. set是按照一定次序存储元素的容器

2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。 set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。

3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行 排序。

4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但set允许根据顺序(begin到end)对 子集进行直接迭代。

5. set在底层是用二叉搜索树(红黑树)实现的。

注意:

1. 与map/multimap不同,map/multimap中存储的是真正的键值对,set中只放 value,但在底层实际存放的是由构成的键值对。

2. set中插入元素时,只需要插入value即可,不需要构造键值对。

3. set中的元素不可以重复(因此可以使用set进行去重)。

4. 使用set的迭代器遍历set中的元素,可以得到有序序列

5. set中的元素默认按照小于来比较

6. set中查找某个元素,时间复杂度为:$log_2 n$

7. set中的元素不允许修改(为什么? 因为底层的红黑树是一个升序结构,如果擅自修改节点的值,可能会破坏树结构)

8. set中的底层使用二叉搜索树(红黑树)来实现。

3.1.2 set的使用

1. set的模板参数列表

T: set中存放元素的类型,实际在底层存储的键值对。

Compare:set中元素默认按照小于来比较

Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理

2. set的构造

3. set的迭代器

4. set的容量

5. set修改操作

6. set的使用举例

#include <set>
void TestSet()
{// 用数组array中的元素构造setint array[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 
6, 8, 0 };set<int> s(array, array+sizeof(array)/sizeof(array[0]));cout << s.size() << endl;// 正向打印set中的元素,从打印结果中可以看出:set可去重for (auto& e : s)cout << e << " ";cout << endl;// 使用迭代器逆向打印set中的元素for (auto it = s.rbegin(); it != s.rend(); ++it)cout << *it << " ";cout << endl;// set中值为3的元素出现了几次cout << s.count(3) << endl;
}

3.2 map

3.2.1 map的介绍

1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元 素。

2. 在map中,键值key通常用于排序和唯一地标识元素,而值value中存储与此键值key关联 的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类 型value_type绑定在一起,为其取别名称为pair

3. 在内部,map中的元素总是按照键值key进行比较排序的。

4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序 对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。

5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。

6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

3.2.2 map的使用

1. map的模板参数说明

key: 键值对中key的类型

T: 键值对中value的类型

Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比 较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户 自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)

Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的 空间配置器 注意:

在使用map时,需要包含头文件。

2. map的构造

3. map的迭代器

4. map的容量与元素访问

问题:当key不在map中时,通过operator获取对应value时会发生什么问题?将键值对插入;

  注意:在元素访问时,有一个与operator[]类似的操作at()(该函数不常用)函数,都是通过 key找到与key对应的value然后返回其引用,不同的是:当key不存在时,operator[]用默认 value与key构造键值对然后插入,返回该默认value,at()函数直接抛异常。

5. map中元素的修改

【总结】

1. map中的的元素是键值对

2. map中的key是唯一的,并且不能修改

3. 默认按照小于的方式对key进行比较

4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列

5. map的底层为平衡搜索树(红黑树),查找效率比较高$O(log_2 N)$

6. 支持[]操作符,operator[]中实际进行插入查找。

3.3 multiset

3.3.1 multiset的介绍

1. multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。

2. 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是组成 的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器 中进行修改(因为元素总是const的),但可以从容器中插入或删除。

3. 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则 进行排序。

4. multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭 代器遍历时会得到一个有序序列。

5. multiset底层结构为二叉搜索树(红黑树)。

注意:

1. multiset中在底层中存储的是的键值对

2. multiset的插入接口中只需要插入即可

3. 与set的区别是,multiset中的元素可以重复,set中value是唯一的

4. 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列

5. multiset中的元素不能修改

6. 在multiset中找某个元素,时间复杂度为$O(log_2 N)$

7. multiset的作用:可以对元素进行排序

3.3.2 multiset的使用

此处只简单演示set与multiset的不同,其他接口接口与set相同,同学们可参考set。

#include <set>
void TestSet()
{int array[] = { 2, 2, 3, 9, 6, 0, 5, 8, 4, 7 };// 注意:multiset在底层实际存储的是<int, int>的键值对multiset<int> s(array, array + sizeof(array)/sizeof(array[0]));for (auto& e : s)cout << e << " ";cout << endl;return 0;
}

3.4 multimap

3.4.1 multimap的介绍

1. Multimaps是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对,其中多个键值对之间的key是可以重复的。

2. 在multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内 容。key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起, value_type是组合key和value的键值对: typedef pair value_type;

3. 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对 key进行排序的。

4. multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代 器直接遍历multimap中的元素可以得到关于key有序的序列。

5. multimap在底层用二叉搜索树(红黑树)来实现。

  注意:multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以 重复的。

3.4.2 multimap的使用

multimap中的接口可以参考map,功能都是类似的。

注意:

1. multimap中的key是可以重复的。

2. multimap中的元素默认将key按照小于来比较

3. multimap中没有重载operator[]操作(为什么?)。

  multimap允许存储多个相同键的元素,这使得operator[]的行为变得不明确。当使用operator[]访问一个存在多个相同键的multimap时,应该返回哪个值?是第一个匹配的值、最后一个匹配的值,还是所有匹配的值?这种歧义使得operator[]在multimap中的实现变得复杂且不符合直观。

4. 使用时与map包含的头文件相同:

4.红黑树模拟实现STL中的map与set

虽然之前已经写过红黑树的模拟实现,但在这里会有所不同。

4.1红黑树的节点定义

enum Color
{Red,Black
};
template<class T>
struct RBTreeNode
{T _data;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Color _col;RBTreeNode(const T& key):_data(key), _left(nullptr), _right(nullptr), _parent(nullptr), _col(Red){}
};

  注意这里只用了T这一个模版参数,因为一个T既可以存储单一类型也可以存储pair类型,因此K模型和KV模型都可以支持!

4.2 红黑树的迭代器

   迭代器的好处是可以方便遍历,是数据结构的底层实现与用户透明。如果想要给红黑树增加迭代 器,需要考虑以前问题:

  begin()与end() STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后, 可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位 置,end()放在最大节点(最右侧节点)的下一个位置,关键是最大节点的下一个位置在哪块? 这里我们将end处给上nullptr,当要执行end--的时候,我们要确保能回到最大节点处。

下面给出红黑树的迭代器封装,思路体现在注释里:

//红黑树的迭代器封装,其实就是对某个节点指针的封装;
//begin位于最小的节点,end位于最大节点的下一个位置
//红黑树的end迭代器,我们设该节点为空指针,且由于我们要满足end--能回到最大元素的位置,就要用到根节点_root
template<class T, class Ref, class Ptr>
struct Iterator
{using Node = RBTreeNode<T>;using Self = Iterator<T, Ref, Ptr>;Node* _node;Node* _root;Iterator(Node* node, Node* root):_node(node),_root(root){}//引用迭代器,直接返回数据data的引用Ref operator*(){return _node->_data;}//it->,返回的是数据data的指针,编译器会优化一次->操作//对于set,->可以直接返回数据,或返回类对象的成员变量//对于map,存储的是pair类型,可以直接用it->first,it->secondPtr operator->(){return &_node->_data;}bool operator==(const Self& it){return _node->_data == it._node->_data;}bool operator!=(const Self& it){return _node != it._node;}//按照顺序返回下一个数据的节点Self& operator++(){//如果当前节点的右侧还有节点,就找出右侧的最小节点if (_node->_right){Node* rightmin = _node->_right;while (rightmin->_left){rightmin = rightmin->_left;}_node = rightmin;}//否则,找出第一个左指针指向当前节点的节点,如果遇到父节点为空了,说明已经到根节点了,// 也就是最初的cur为最大节点,_node最后就应该指向空指针(end),符合迭代器思想else{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}//按照顺序返回上一个数据的节点Self& operator--(){//这种情况是从end--,应该回到最大节点处if (_node == nullptr){Node* rightmax = _root;while (rightmax->_right){rightmax = rightmax->_right;}_node = rightmax;}//如果当前节点的左侧还有节点,就找出左侧的最大节点else if (_node->_left){Node* leftmax = _node->_left;while (leftmax->_right){leftmax = leftmax->_right;}_node = leftmax;}//否则,找出第一个右指针指向当前节点的节点,如果遇到父节点为空了,说明已经到根节点了,// 也就是最初的cur为最小节点,_node最后就应该指向空指针(end),符合迭代器思想else{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}
};

4.3改造红黑树

  因为关联式容器中存储的是的键值对:

  T是存储的数据类型,可能是单一类型,也可能是pair类型,因此我们无法确定T的键值类型以及如何取键值,
   KeyofT是取键值的方式,Compare是比较逻辑

//因为T是存储的数据类型,可能是单一类型,也可能是pair类型,因此我们无法确定T的键值类型以及如何取键值,
// KeyofT是取键值的方式,Compare是比较逻辑
template<class K, class T, class KeyofT,class Compare = myless<K>>
class RBTree
{
public:using Node = RBTreeNode<T>;using iterator = Iterator<T, T&, T*>;using const_iterator = Iterator<T, const T&, const T*>;iterator begin(){Node* leftmin = _root;while (leftmin && leftmin->_left){leftmin = leftmin->_left;}return iterator(leftmin, _root);}iterator end(){return iterator(nullptr, _root);}const_iterator begin() const{Node* leftmin = _root;while (leftmin && leftmin->_left){leftmin = leftmin->_left;}return const_iterator(leftmin, _root);}const_iterator end() const{return const_iterator(nullptr, _root);}RBTree() = default;RBTree(const RBTree<K, T, KeyofT, Compare>& t){_root = Copy(t._root);}Node* Copy(Node* root){if (root == nullptr){return nullptr;}Node* newroot = new Node(root->_data);newroot->_parent = root->_parent;newroot->_color = root->_color;newroot->_left = Copy(root->_left);newroot->_right = Copy(root->_right);return newroot;}RBTree<K, T, KeyofT,Compare >& operator=(RBTree t){swap(_root, t._root);return *this;}~RBTree(){Destroy(_root);_root = nullptr;}void Destroy(Node* root){if (root == nullptr){return;}Destroy(root->_left);Destroy(root->_right);delete root;}void inorder(){Inorder(_root);}void Inorder(Node* root){if (root == nullptr){return;}Inorder(root->_left);cout << root->_data.first << ' ' << root->_data.second << endl;Inorder(root->_right);}iterator find(const K& key){Compare comp;KeyofT key;Node* cur = _root;while (cur){if (comp(key(cur->_data), key)){cur = cur->_right;}else if (!comp(key(cur->_data), key)){cur = cur->_left;}else{return iterator(cur, _root);}}return end();}pair<iterator,bool> insert( T& data){Compare comp;KeyofT key;if (_root == nullptr){_root = new Node(data);_root->_color = Black;return make_pair(iterator(_root,_root),true);}Node* cur = _root;Node* parent = nullptr;while (cur){if (comp(key(cur->_data), key(data))){parent = cur;cur = cur->_right;}else if (!comp(key(cur->_data), key(data))){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur, _root), false);}}cur = new Node(data);if (comp(key(parent->_data), key(data))){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//进行颜色调整while (parent && parent->_color == Red){Node* grand = parent->_parent;Node* uncle = nullptr;if (parent == grand->_left){uncle = grand->_right;if (uncle && uncle->_color == Red){parent->_color = uncle->_color = Black;grand->_color = Red;cur = grand;parent = cur->_parent;}else{if (cur == parent->_left){RotateR(grand);grand->_color = Red;parent->_color = Black;break;}else{RotateL(parent);RotateR(grand);cur->_color = Black;grand->_color = Red;break;}}}else{uncle = grand->_left;if (uncle && uncle->_color == Red){parent->_color = uncle->_color = Black;grand->_color = Red;cur = grand;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grand);grand->_color = Red;parent->_color = Black;break;}else{RotateR(parent);RotateL(grand);cur->_color = Black;grand->_color = Red;break;}}}}_root->_color = Black;return make_pair(iterator(cur, _root), true);}
private:void RotateR(Node* parent){Node* cur = parent->_left;Node* cr = cur->_right;parent->_left = cr;if (cr){cr->_parent = parent;}Node* pparent = parent->_parent;cur->_right = parent;parent->_parent = cur;if (pparent == nullptr){_root = cur;cur->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = cur;}else{pparent->_right = cur;}cur->_parent = pparent;}}void RotateL(Node* parent){Node* cur = parent->_right;Node* cr = cur->_left;parent->_right = cr;if (cr){cr->_parent = parent;}Node* pparent = parent->_parent;cur->_left = parent;parent->_parent = cur;if (pparent == nullptr){_root = cur;cur->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = cur;}else{pparent->_right = cur;}cur->_parent = pparent;}}
private:Node* _root = nullptr;
};

4.4 map的模拟实现

map的底层结构就是红黑树,因此在map中直接封装一棵红黑树,然后将其接口包装下即可

#include "RBTree.hpp"template<class K,class V>
class Map
{
public:class KeyofT{public:const K& operator()(const pair<K,V>& x){return x.first;}};using iterator = typename RBTree<K, pair<const K,V>, KeyofT>::iterator;using const_iterator = typename RBTree<K, pair<const K, V>, KeyofT>::const_iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin()const{return _t.begin();}const_iterator end()const{return _t.end();}iterator find(const K& x){return _t.find(x);}pair<iterator, bool> insert(  pair<const K, V> x){return _t.insert(x);}V& operator[](const K& key){pair<iterator, bool> ret = insert({ key,K() });auto it = ret.first;return it->second;}
private:RBTree<K, pair<const K, V>, KeyofT> _t;
};

4.5 set的模拟实现

  set的底层为红黑树,因此只需在set内部封装一棵红黑树,即可将该容器实现出来(具体实现可参 考map)。

#include "RBTree.hpp"template<class K>
class Set
{
public:class KeyofT{public:const K& operator()(const K& x){return x;}};using iterator = typename RBTree<K,const K, KeyofT>::iterator;using const_iterator = typename RBTree<K, const K, KeyofT>::const_iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin()const{return _t.begin();}const_iterator end()const{return _t.end();}iterator find(const K& x){return _t.find(x);}pair<iterator, bool> insert(const K& x){return _t.insert(x);}
private:RBTree<K, const K, KeyofT> _t;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919775.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919775.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

贪吃蛇--C++实战项目(零基础)

视频地址&#xff1a;C语言必学项目&#xff1a;贪吃蛇&#xff01; 贪吃蛇游戏框架 ├── 基础框架 │ ├── 头文件引入 │ ├── 常量和宏定义 │ └── 窗口初始化 │ ├── 数据结构系统 │ ├── Pos结构体(位置和颜色) │ ├── Snake结构体(蛇的属性) │ ├──…

unity资源领取反作弊工具加密器

https://assetstore.unity.com/packages/tools/utilities/anti-cheat-pro-2025-3006260元购码GUARDINGPEARSOFTWARE

FPGA设计中的信号完整性量化与优化:探索高速数字系统的关键路径

在高速FPGA设计中&#xff0c;信号完整性&#xff08;Signal Integrity, SI&#xff09;已成为确保系统稳定、可靠运行的核心要素之一。随着数据传输速率的不断提升和电路规模的日益复杂&#xff0c;信号在传输过程中受到的干扰和畸变问题日益凸显。因此&#xff0c;如何有效量…

`strncasecmp` 字符串比较函数

1) 函数的概念与用途 strncasecmp 是 C 语言中一个非常实用的字符串处理函数&#xff0c;它执行不区分大小写的字符串比较&#xff0c;但只比较前 n 个字符。这个函数的名字来源于"string n case-compare"&#xff08;字符串前n个字符不区分大小写比较&#xff09;。…

软件安装教程(一):Visual Studio Code安装与配置(Windows)

文章目录前言一、Visual Studio Code下载二、安装步骤&#xff08;Windows&#xff09;1. GUI安装2. 命令行安装三、首次启动后建议的快速配置&#xff08;几分钟完成&#xff09;四、常见问题 & 小贴士总结前言 Visual Studio Code&#xff08;VS Code&#xff09;是一款…

JavaSSM框架从入门到精通!第三天(MyBatis(二))!

四、Mapper 的动态代理1. 引入 在上面的 CURD 例子中&#xff0c;我们发现&#xff1a;Dao 层的实现类的每一个方法仅仅是通过 SqlSession 对象的相关 API 定位到映射文件 mapper 中的 SQL 语句&#xff0c;真正对数据库操作的工作实际上是有 Mybatis 框架通过 mapper 中的 SQL…

大模型应用发展与Agent前沿技术趋势(下)

Agent技术的行业应用与实践案例 金融领域的Agent应用 金融行业是大模型Agent技术应用最为广泛的领域之一&#xff0c;涵盖了风险评估、投资决策、客户服务等多个方面。在金融风控领域&#xff0c;Agent系统通过结合大模型的语义理解能力和强化学习的决策优化能力&#xff0c;能…

94. 城市间货物运输 I, Bellman_ford 算法, Bellman_ford 队列优化算法

94. 城市间货物运输 IBellman_ford 算法Bellman_ford 算法 与 dijkstra算法 相比通用性更强。dijkstra算法解决不了负权边的问题&#xff0c;因为Dijkstra基于贪心策略&#xff0c;一旦一个节点被从队列中取出&#xff08;标记为已解决&#xff09;&#xff0c;它就假定已经找到…

如何使用Prometheus + Grafana + Loki构建一个现代化的云原生监控系统

如何使用 Prometheus + Grafana + Loki 构建一个现代化的云原生监控系统。这套组合被誉为监控领域的“瑞士军刀”,功能强大且生态极佳。 一、核心组件概念介绍 在搭建之前,深刻理解每个组件的角色和职责至关重要。 1. Prometheus(指标监控与时序数据库) 角色:系统的“核…

JavaScript Object 操作方法及 API

一、对象创建方式1.字面量创建&#xff08;最常用&#xff09;const obj { name: "张三", age: 25 };2.构造函数创建const obj new Object(); obj.name "李四";3.Object.create()&#xff08;指定原型&#xff09;const proto { greet: () > "…

pta乙级题目day1

第1天&#xff1a;输入输出与运算&#xff08;6题&#xff09;1001 害死人不偿命的(3n1)猜想&#xff08;基础运算&#xff09;★1006 换个格式输出整数&#xff08;格式化输出&#xff09;★1016 部分AB&#xff08;数字提取&#xff09;★★1046 划拳&#xff08;多输入处理&…

在VSCode中配置.NET项目的tasks.json以实现清理、构建、热重载和发布等操作

在 VS Code 中配置 .NET 开发任务的完整指南 引言 重要提醒&#xff1a;对于 .NET 开发&#xff0c;强烈推荐使用 Visual Studio&#xff0c;它提供了最完整和稳定的开发体验。如果你像我一样"蛋疼"想要尝试 VS Code&#xff0c;请确保安装了 C# 开发扩展包&#x…

EmEditor文本编辑器v25.3.0专业版,专业文本编辑,高亮显示,无限撤消

[软件名称]: EmEditor文本编辑器v25.3.0专业版 [软件大小]: 37.7 MB [软件大小]: 夸克网盘 | 百度网盘 软件介绍 EmEditor 是一款功能强大且非常实用的文本编辑器。它启动速度快&#xff0c;完全可以替代 Windows 自带的记事本&#xff0c;轻松应对日常文本编辑任务。它对 …

【spring security】权限管理组件执行流程详解

&#x1f3af; 权限管理组件执行流程详解 &#x1f3d7;️ 组件架构图 ┌─────────────────────────────────────────────────────────────┐ │ HTTP请求 …

redis怎么保障双写一致性

redis做为缓存&#xff0c;mysql的数据如何与redis进行同步呢&#xff1f;&#xff08;双写一致性&#xff09;候选人&#xff1a;嗯&#xff01;就说我最近做的这个项目&#xff0c;里面有xxxx&#xff08;根据自己的简历上写&#xff09;的功能&#xff0c;需要让数据库与red…

异常值检测:孤立森林模型(IsolationForest)总结

目录一、前言二、孤立森林算法2.1 算法简介2.2 基本原理2.3 算法步骤2.4 异常分数计算方式2.5 python调用方式三、python代码示例四、小结五、参考学习一、前言 近期在研究构建寿命预测模型&#xff0c;相信很多数据人都懂建模的过程&#xff0c;其实有80%的时间都是在和数据处…

Docker容器化部署实战:Tomcat与Nginx服务配置指南

部署Tomcat搜索镜像 使用以下命令搜索可用的Tomcat镜像&#xff1a;docker search tomcat拉取镜像 拉取官方Tomcat镜像&#xff1a;docker pull tomcat创建专用目录 为Tomcat配置和数据创建专用目录&#xff1a;mkdir tomcat运行临时容器并复制配置文件 启动临时容器以复制配置…

Go语言实战案例-使用SQLite实现本地存储

在开发工具类软件、桌面应用或者移动端时&#xff0c;我们经常需要一个轻量级数据库来做 本地存储。相比 MySQL、Postgres 等服务型数据库&#xff0c;SQLite 体积小、零配置、单文件存储&#xff0c;非常适合这种场景。Go 语言通过 GORM SQLite 驱动 就能轻松实现。本文将带你…

云计算学习100天-第23天

主机192.168.88.5 安装nginx#安装编译工具&#xff0c;正则表达式依赖包&#xff0c;SSL加密依赖包 yum -y install gcc make pcre-devel openssl-devel tar -xf /root/lnmp_soft.tar.gz cd lnmp_soft/ tar -xf nginx-1.22.1.tar.gz cd nginx-1.22.1/ #指定安装路径&…

【生成树+环】题解:P3907 环的异或_图论_环_异或_搜索_算法竞赛_C++

推销洛谷博客&#xff1a;https://www.luogu.com.cn/article/znmr9iu9 Link&#xff1a;Luogu - P3907 这里默认题目中指的环都是“简单环”&#xff08;即没有“环套环”的情况&#xff09;。 众所周知&#xff0c;树是图的一种特殊情况&#xff0c;且一定无环。如果我们想…