当前位置: 首页 > news >正文

【STL】10.set与map的模拟实现

一、源码及框架分析

SGI-STL30版本源代码,map和set的源代码在map/set/stl_map.h/stl_set.h/stl_tree.h等及个头文件中。
map和set的实现结构框架核心部分截取出来如下:

// set
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_set.h>
#include <stl_multiset.h>
// map
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_map.h>
#include <stl_multimap.h>// stl_set.h
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:// typedefs:typedef Key key_type;typedef Key value_type;
private:typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;rep_type t; // red-black tree representing set
};
// stl_map.h
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:// typedefs:typedef Key key_type;typedef T mapped_type;typedef pair<const Key, T> value_type;
private:typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;rep_type t; // red-black tree representing map
};// stl_tree.h
struct __rb_tree_node_base
{typedef __rb_tree_color_type color_type;typedef __rb_tree_node_base* base_ptr;color_type color; base_ptr parent;base_ptr left;base_ptr right;
};
// stl_tree.h
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc = alloc>
class rb_tree {
protected:typedef void* void_pointer;typedef __rb_tree_node_base* base_ptr;typedef __rb_tree_node<Value> rb_tree_node;typedef rb_tree_node* link_type;typedef Key key_type;typedef Value value_type;
public:// insert⽤的是第⼆个模板参数做形参 pair<iterator,bool> insert_unique(const value_type& x);// erase和find⽤第⼀个模板参数做形参 size_type erase(const key_type& x);iterator find(const key_type& x);
protected:size_type node_count; // keeps track of size of treelink_type header;
};
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{typedef __rb_tree_node<Value>* link_type;Value value_field;}

• 通过下图对框架的分析,我们可以看到源码中rb_tree用了一个巧妙的泛型思想实现,rb_tree是实现key的搜索场景,还是key/value的搜索场景不是直接写死的,而是由第二个模板参数Value决定_rb_tree_node中存储的数据类型。
• set实例化rb_tree时第二个模板参数给的是key,map实例化rb_tree时第二个模板参数给的是pair<const key , T>,这样一颗红黑树既可以实现key搜索场景的set,也可以实现key/value搜索场景的map。
• 要注意⼀下,源码里面模板参数是用T代表value,而内部写的value_type不是我们我们日常key/value场景中说的value,源码中的value_type反而是红黑树结点中存储的真实的数据的类型。
• rb_tree第二个模板参数Value已经控制了红黑树结点中存储的数据类型,为什么还要传第一个模板参数Key呢?尤其是set,两个模板参数是⼀样的,这是很多同学这时的一个疑问。要注意的是对于map和set,find/erase时的函数参数都是Key,所以第一个模板参数是传给find/erase等函数做形参的类型的。对于set而言两个参数是一样的,但是对于map而言就完全不一样了,map insert的是pair对象,但是find和ease的是Key对象。
在这里插入图片描述

二、模拟实现 set 和 map

2.1 实现出符合要求的红黑树

2.1.1 iterator 与 reverse_iterator

iterator实现思路分析
• iterator实现的大框架跟list的iterator思路是一致的,用一个类型封装结点的指针,再通过重载运算符实现迭代器像指针一样访问的行为。
• 这里的难点是operator++和operator–的实现。之前使用部分,我们分析了,map和set的迭代器走的是中序遍历,左子树->根结点->右子树,那么begin()会返回中序第一个结点的iterator也就是最左节点的迭代器。
• 迭代器++的核心逻辑就是不看全局,只看局部,只考虑当前中序局部要访问的下一个结点。迭代器++时,如果it指向的结点的右子树不为空,代表当前结点已经访问完了,要访问下一个结点是右子树的中序第一个,一棵树中序第一个是最左结点,所以直接找右子树的最左结点即可;如果it指向的结点的右子树空,代表当前结点已经访问完了且当前结点所在的子树也访问完了,要访问的下一个结点在当前结点的祖先里面,所以要沿着当前结点到根的祖先路径向上找。如果当前结点是父亲的左,根据中序左子树->根结点->右子树,那么下一个访问的结点就是当前结点的父亲;如果当前结点是父亲的右,根据中序左子树->根结点->右子树,当前当前结点所在的子树访问完了,当前结点所在父亲的子树也访问完了,那么下一个访问的需要继续往根的祖先中去找,直到找到孩子是父亲左的那个祖先就是中序要遍历的下一个结点。
• end()如何表示呢?stl源码中,红黑树增加了一个哨兵位头结点做为end(),这哨兵位头结点和根互为父亲,左指向最左结点,右指向最右结点。
• 迭代器–的实现跟++的思路完全类似,逻辑正好反过来即可,因为他访问顺序是右子树->根结点->左子树。
• set的iterator也不支持修改,我们把set的第二个模板参数改成const K即可, RBTree<K, const K, SetKeyOfT> _t;
• map的iterator不支持修改key但是可以修改value,我们把map的第二个模板参数pair的第一个参数改成const K即可, RBTree<K, pair<const K, V>, MapKeyOfT> _t;
• 至于reverse_iterator的实现和iterator类似,就不多赘述,具体实现看下面的代码。

通过上面的叙述我们了解到整体需要从结点的定义开始改造,即定义哨兵结点。

2.1.2 改造红黑树的代码

#pragma once#include<iostream>
#include<assert.h>
using namespace std;
//节点颜色
enum Colour
{RED,BLACK
};//红黑树的节点
//K是用来查找的,T是用来插入的
//set中T是key,map中T是pair<key,value>
template<class T>
struct RBTreeNode
{T _t;//dataRBTreeNode* _left;RBTreeNode* _right;RBTreeNode* _parent;Colour _col;RBTreeNode(const T& t = T(), Colour col = RED):_t(t),_left(nullptr),_right(nullptr),_parent(nullptr),_col(col){}
};
//红黑树的迭代器
template<class T, class Ref, class Ptr>
struct RBTreeIterator
{typedef RBTreeNode<T> Node;Node* _node;//要操作的节点RBTreeIterator(Node* node) :_node(node) {}typedef RBTreeIterator Self;//++itSelf& operator++(){Node* cur = _node;if (cur->_right){Node* LeftMost = cur->_right;while (LeftMost->_left){LeftMost = LeftMost->_left;}_node = LeftMost;}else{Node* parent = cur->_parent;while (parent->_right == cur){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}//it++Self operator++(int){Self temp(*this);++*this;return temp;}//--itSelf& operator--(){Node* cur = _node;//end()时if (_node->_parent->_parent == _node && _node->_col == RED){_node = _node->_right;}else if (cur->_left){Node* RightMost = cur->_left;while (RightMost->_right){RightMost = RightMost->_right;}_node = RightMost;}else{Node* parent = cur->_parent;while (parent->_left == cur){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}//it--Self operator--(int){Self temp(*this);--*this;return temp;}Ref operator*(){return _node->_t;}Ptr operator->(){return &_node->_t;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}
};
//红黑树的反向迭代器
template<class T, class Ref, class Ptr>
struct RBTreeReverseIterator
{typedef RBTreeNode<T> Node;Node* _node;//要操作的节点RBTreeReverseIterator(Node* node) :_node(node) {}typedef RBTreeReverseIterator Self;//++itSelf& operator--(){Node* cur = _node;if (cur->_right){Node* LeftMost = cur->_right;while (LeftMost->_left){LeftMost = LeftMost->_left;}_node = LeftMost;}else{Node* parent = cur->_parent;while (parent->_right == cur){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}//it++Self operator++(int){Self temp(*this);++*this;return temp;}//--itSelf& operator++(){Node* cur = _node;//end()时if (_node->_parent->_parent == _node && _node->_col == RED){_node = _node->_right;}else if (cur->_left){Node* RightMost = cur->_left;while (RightMost->_right){RightMost = RightMost->_right;}_node = RightMost;}else{Node* parent = cur->_parent;while (parent->_left == cur){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}//it--Self operator--(int){Self temp(*this);--*this;return temp;}Ref operator*(){return _node->_t;}Ptr operator->(){return &_node->_t;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}
};//红黑树
template<class K, class T, class KeyOfT>
class RBTree
{typedef RBTreeNode< T> Node;void destory(Node* root){if (root == nullptr)return;//必须后续销毁节点destory(root->_left);root->_left = nullptr;destory(root->_right);root->_right = nullptr;delete root;root = nullptr;}
public:RBTree(){_header = new Node(T());}//拷贝构造RBTree(const RBTree& rbt){_header = new Node(T());for (const auto e : rbt){insert(e);}}RBTree(initializer_list<T> il){_header = new Node(T());for (const auto& e : il)insert(e);}//赋值重载RBTree& operator=(const RBTree& bst){//现代写法RBTree temp(bst);std::swap(_header, temp._header);return *this;}// 析构~RBTree(){destory(_header->_parent);delete _header;_header = nullptr;}typedef RBTreeIterator<T, T&, T*> iterator;typedef RBTreeIterator<T, const T&, const T*> const_iterator;typedef RBTreeReverseIterator<T, T&, T*> reverse_iterator;typedef RBTreeReverseIterator<T, const T&, const T*> const_reverse_iterator;//迭代器iterator begin(){return iterator(_header->_left);}const_iterator begin() const{return const_iterator(_header->_left);}iterator end(){return iterator(_header);}const_iterator end() const{return const_iterator(_header);}//反向迭代器reverse_iterator rbegin(){return reverse_iterator(_header->_right);}const_reverse_iterator rbegin()const{return const_reverse_iterator(_header->_right);}reverse_iterator rend(){return reverse_iterator(_header);}const_reverse_iterator rend()const{return const_reverse_iterator(_header);}//此时需要注意key是set中的key,是map中pair<key,value>中的key,// 因此我们需要取出想要的keyiterator find(const K& key) const{Node* cur = _header->_parent;//指向根节点while (cur){if (key < KeyOfT()(cur->_t)){cur = cur->_left;}else if (key > KeyOfT()(cur->_t)){cur = cur->_right;}else{return iterator(cur);}}return iterator(_header);}pair<iterator, bool> insert(const T& t){if (_header->_parent == nullptr){_header->_parent = new Node(t);_header->_parent->_col = BLACK;_header->_parent->_parent = _header;return { iterator(_header->_parent),true };}//查找结点Node* parent = _header;Node* cur = _header->_parent;while (cur){if (KeyOfT()(t) < KeyOfT()(cur->_t)){parent = cur;cur = cur->_left;}else if (KeyOfT()(t) > KeyOfT()(cur->_t)){parent = cur;cur = cur->_right;}else{return { iterator(cur), false };}}//插入节点cur = new Node(t);cur->_parent = parent;if (KeyOfT()(t) < KeyOfT()(parent->_t))parent->_left = cur;elseparent->_right = cur;//保存cur,留待返回Node* ret = cur;//调整颜色//情况一:parent存在且为黑,不需要调整//情况二:parent存在且为红,需要调整while (parent != _header && parent->_col == RED){//确定 g 和 u 节点Node* grandfather = parent->_parent;Node* uncle = nullptr;if (parent == grandfather->_left)uncle = grandfather->_right;elseuncle = grandfather->_left;//在情况二下又有如下情况://情况1:unclude存在且为红if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续向上调整cur = grandfather;parent = cur->_parent;}//情况2:uncle不存在或uncle为黑else if (!uncle || uncle->_col == BLACK){//parent 是 grandfather 的左孩子if (parent == grandfather->_left){//cur 是 parent 的左孩子if (cur == parent->_left){//旋转加变色RotateRight(grandfather);parent->_col = BLACK;grandfather->_col = RED;}//cur 是 parent 的右孩子else{//旋转加变色RotateLeftThenRight(grandfather);cur->_col = BLACK;grandfather->_col = RED;}}//parent 是 grandfather 的右孩子else{//cur 是 parent 的左孩子if (cur == parent->_left){//旋转加变色RotateRightThenLeft(grandfather);cur->_col = BLACK;grandfather->_col = RED;}//cur 是 parent 的右孩子else{//旋转加变色RotateLeft(grandfather);parent->_col = BLACK;grandfather->_col = RED;}}break;//调整好能退出了}else{assert(false);//逻辑错误,理论上不可能走到}}//保证根节点必须是黑色的_header->_parent->_col = BLACK;_header->_left = LeftMost();_header->_right = RightMost();return { iterator(ret), true };}bool empty(){return _header->_parent == nullptr;}size_t size(){size_t count = 0;auto it = begin();while (it != end()){count++;++it;}return count;}void clear(){destory(_header->_parent);_header->_parent = nullptr;}
private:Node* LeftMost(){Node* MostLeftChild = _header->_parent;while (MostLeftChild->_left){MostLeftChild = MostLeftChild->_left;}return MostLeftChild;}Node* RightMost(){Node* MostRightChild = _header->_parent;while (MostRightChild->_right){MostRightChild = MostRightChild->_right;}return MostRightChild;}void RotateLeft(Node* parent){//保存节点,后面链接Node* parentparent = parent->_parent;Node* sub = parent->_right;Node* subleft = sub->_left;//重新链接parent->_right = subleft;if (subleft)subleft->_parent = parent;sub->_left = parent;parent->_parent = sub;//和上面的节点链接if (parentparent == _header){//说明parent原来是根节点_header->_parent = sub;sub->_parent = _header;}else{if (parentparent->_left == parent){//原来是上面节点的左子树parentparent->_left = sub;}else{parentparent->_right = sub;}sub->_parent = parentparent;}}void RotateRight(Node* parent){//保存节点,后面链接Node* parentparent = parent->_parent;Node* sub = parent->_left;Node* subright = sub->_right;//重新链接parent->_left = subright;if (subright)subright->_parent = parent;sub->_right = parent;parent->_parent = sub;//和上面的节点链接if (parentparent == _header){//说明parent原来是根节点_header->_parent = sub;sub->_parent = _header;}else{if (parentparent->_left == parent){//原来是上面节点的左子树parentparent->_left = sub;}else{parentparent->_right = sub;}sub->_parent = parentparent;}}void RotateLeftThenRight(Node* parent){RotateLeft(parent->_left);RotateRight(parent);}void RotateRightThenLeft(Node* parent){RotateRight(parent->_right);RotateLeft(parent);}
private:Node* _header;
};

2.2 复用红黑树实现 set

#pragma once#include"RBTree.h"template<class K>
class set
{typedef const K T;//用以插入struct KeyOfT{const K& operator()(const T& key){return key;}};typedef typename RBTree<K, T, KeyOfT>::iterator iterator;typedef typename RBTree<K, T, KeyOfT>::const_iterator const_iterator;typedef typename RBTree<K, T, KeyOfT>::reverse_iterator reverse_iterator;typedef typename RBTree<K, T, KeyOfT>::const_reverse_iterator const_reverse_iterator;
public:set() = default;set(initializer_list<T> il){_rbt = { il };}//迭代器iterator begin(){return _rbt.begin();}const_iterator begin()const{return _rbt.begin();}iterator end(){return _rbt.end();}const_iterator end() const{return _rbt.end();}//反向迭代器reverse_iterator rbegin(){return _rbt.rbegin();}const_reverse_iterator rbegin()const{return _rbt.rbegin();}reverse_iterator rend(){return _rbt.rend();}const_reverse_iterator rend() const{return _rbt.rend();}bool empty(){return _rbt.empty();}size_t size(){return _rbt.size();}void clear(){_rbt.clear();}iterator find(const K& key)const{return _rbt.find(key);}pair<iterator, bool> insert(const T& t){return _rbt.insert(t);}private:RBTree<K, T, KeyOfT> _rbt;
};

2.3 复用红黑树实现 map

#pragma once#include"RBTree.h"template<class K, class V>
class map
{typedef pair<const K, V> T;struct KeyOfT{const K& operator()(const T& data){return data.first;}};typedef typename RBTree<K, T, KeyOfT>::iterator iterator;typedef typename RBTree<K, T, KeyOfT>::const_iterator const_iterator;typedef typename RBTree<K, T, KeyOfT>::reverse_iterator reverse_iterator;typedef typename RBTree<K, T, KeyOfT>::const_reverse_iterator const_reverse_iterator;
public:map() = default;map(initializer_list<T> il){_rbt = { il };}//迭代器iterator begin(){return _rbt.begin();}const_iterator begin()const{return _rbt.begin();}iterator end(){return _rbt.end();}const_iterator end() const{return _rbt.end();}//反向迭代器reverse_iterator rbegin(){return _rbt.rbegin();}const_reverse_iterator rbegin()const{return _rbt.rbegin();}reverse_iterator rend(){return _rbt.rend();}const_reverse_iterator rend() const{return _rbt.rend();}bool empty(){return _rbt.empty();}size_t size(){return _rbt.size();}void clear(){_rbt.clear();}iterator find(const K& key)const{return _rbt.find(key);}pair<iterator, bool> insert(const pair<const K, V>& kv){return _rbt.insert(kv);}V& operator[](const K& key){pair<iterator, bool> ret = insert({ key, V() });iterator it = ret.first;return it->second;}
private:RBTree < K, pair<const K, V>, KeyOfT> _rbt;//key 不能修改
};

相关文章:

【STL】10.set与map的模拟实现

一、源码及框架分析 SGI-STL30版本源代码&#xff0c;map和set的源代码在map/set/stl_map.h/stl_set.h/stl_tree.h等及个头文件中。 map和set的实现结构框架核心部分截取出来如下&#xff1a; // set #ifndef __SGI_STL_INTERNAL_TREE_H #include <stl_tree.h> #endif …...

Playwright(Java版) - 8: Playwright 元素交互的高级应用

在自动化测试中&#xff0c;处理复杂的页面交互是常见的需求。例如&#xff0c;应对动态加载的元素、处理弹窗与对话框、模拟拖放操作&#xff0c;甚至在绘图板上进行绘图操作。 1 动态元素与弹窗处理 1.1 动态元素的加载与等待 动态页面可能会导致元素在操作时尚未完全加载&…...

播放器开发之ffmpeg 硬件解码方案

硬件编解码的概念 硬件编解码是⾮CPU通过烧写运⾏视频加速功能对⾼清视频流进⾏编解码&#xff0c;其中⾮CPU可包括GPU、FPGA或者 ASIC等独⽴硬件模块&#xff0c;把CPU⾼使⽤率的视频解码⼯作从CPU⾥分离出来&#xff0c;降低CPU的使⽤负荷&#xff0c;使得平台能 ⾼效且流畅…...

n、nvm、nrm、pnpm、yarn各种指令大全

n mac的版本管理工具&#xff08;可能与nvm冲突&#xff09; 安装 # 使用 npm / yarn npm i -g n yarn global add n # 使用 brew brew install n环境变量 export PATH"/usr/local/n/versions/node:$PATH"命令详解 版本查看 # 查看 n 版本 n --version/-V # 查…...

数据库管理-根据日期字段进行数据筛选更新数据

项目场景 数据插入、更新、查询 数据库中一张审计表格用来记录数据的操作包括数据的id&#xff0c;数据名称sjmc&#xff0c;数据状态sjzt&#xff0c;数据创建时间createtime&#xff0c;数据更新时间updatetime。 具体需求如下&#xff1a; 根据数据名称更新sjzt和update…...

03. 运算符

一、运算符与表达式 运算符 就是对字面量或者变量进行操作的符号&#xff1b;表达式 是指用运算符把字面量或者变量连接起来&#xff0c;符合 Python 语法的式子。不同运算符连接的表达式体现的是不同类型的表达式&#xff1b;Python 中的运算符主要包括 算术运算符、赋值运算符…...

【最优清零方案——贪心+滑动窗口+线段树】

题目 代码 #include <bits/stdc.h> using namespace std; using ll long long; const int N 1e6 10; int a[N]; struct node {int l, r;int m, p, lazy; } tr[4 * N]; void pushup(node &u, node &l, node &r) {if (l.m r.m){u.m l.m;u.p max(l.p, r.…...

一个点绕任意点旋转后的点的坐标

在平面坐标上&#xff0c;任意点P(x1,y1)&#xff0c;绕一个坐标点Q(x2,y2)逆时针旋转θ角度后,新的坐标设为(x, y)的计算公式&#xff1a; x (x1 - x2)*cos(θ) - (y1 - y2)*sin(θ) x2 ; y (x1 - x2)*sin(θ) (y1 - y2)*cos(θ) y2 ; 另一个场景应用&#xff0c;坐标轴绕…...

大数据面试题每日练习--HDFS是如何工作的?

HDFS&#xff08;Hadoop Distributed File System&#xff09;是一个分布式文件系统&#xff0c;设计用于存储非常大的文件。它的主要工作原理如下&#xff1a; NameNode&#xff1a;管理文件系统的命名空间&#xff0c;维护文件目录树和文件元数据信息。NameNode记录每个文件…...

Python的3D可视化库 - vedo (2)visual子模块 基本可视化行为

文章目录 1. visual模块的继承关系2. 基类CommonVisual的方法2.1 获取对象信息2.1.1 对象本身信息2.1.2 对象的查找表2.1.3 对象标量范围2.1.4 对象缩略图 2.2 呈现对象2.2.1 在窗口显示1.2.2 对象可见性 2.2.3 对象颜色2.2.4 对象透明度 2.3 添加标度条2.3.1 2D标度条2.3.2 3D…...

Java AIO(NIO.2)

Java AIO&#xff08;Asynchronous I/O&#xff0c;异步I/O&#xff09;&#xff0c;也被称为NIO.2&#xff0c;是Java平台提供的一种处理异步输入/输出操作的机制。作为Java NIO&#xff08;New I/O&#xff09;的扩展&#xff0c;AIO引入了一些新的API和特性&#xff0c;旨在…...

Flink 常用问题及常用配置(有用)

一、Flink 常用问题及常用配置 参数 示例 说明 execution.checkpointing.interval 3min Checkpoint 触发间隔 state.backend rocksdb / filesystem 用于设置statebackend类型, 默认会以内存为statebackend(无法支持大状态) taskmanager.memory.jvm-overhead.max 204…...

RocketMQ: 消息过滤,通信组件,服务发现

消息过滤 1 ) 简单消息过滤 /*** 订阅指定topic下tags分别等于 TagA 或 TagC 或 TagD */consumer.subscribe("TopicTest1", "TagA || TagC || TagD");如以上代码所示&#xff0c;简单消息过滤通过指定多个 Tag 来过滤消息&#xff0c;过滤的动作在服务器进…...

linux ubuntu的脚本知

目录 一、变量的引用 二、判断指定的文件是否存在 三、判断目录是否存在 四、判断最近一次命令执行是否成功 五、一些比较符号 六、"文件"的读取和写入 七、echo打印输出 八、ubuntu切换到root用户 N、其它可以参考的网址 脚本功能强大&#xff0c;用起来也…...

HTTP有哪些风险?是怎么解决的?

一、风险 HTTP是通过明文传输的&#xff0c;存在窃听风险、篡改风险以及冒充风险。 二、如何解决 HTTPS在HTTP的下层加了一个SSL/TLS层&#xff0c;保证了安全&#xff0c;通过混合加密解决窃听风险、数字签名解决篡改风险、数字证书解决冒充风险。 &#xff08;1&#xff0…...

3.12MayBeSomeLinearAlgebra

X是M*(D1),XT为&#xff08;D1)*M Ω是一行D1列&#xff0c;X乘以欧米噶是M行D1列 行是说样本个数&#xff0c;列是特征数量 如果是小样本&#xff0c;那么可能会出现特征数量大于样本个数 如果MD*DM就是M*M&#xff0c;...

学习日志015--python单链表

创建 class Node:def __init__(self,data):# 数据域self.data data# 链接域self.next Noneclass LinkList:def __init__(self,):# 初始化头节点self.head None# 记录链表的长度self.size 0 增加 #头插def insert_head(self,value):# 创建新节点node Node(value)q self…...

如何在Windows右键新建菜单中添加自定义项

Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\.py] "Python.File"[HKEY_CLASSES_ROOT\.py\ShellNew] "NullFile"""[HKEY_CLASSES_ROOT\Python.File] "FriendlyTypeName""文本.py"[HKEY_CLASSES_ROOT\Python.Fil…...

Spring Boot 3.0废弃了JavaEE,改用了Jakarta EE

Spring Boot 3.0废弃了JavaEE&#xff0c;改用了Jakarta EE 历史背景 javax变成Jakarta的主要原因是因为Java EE项目从Oracle转移到了Eclipse Foundation&#xff0c;并改名为Jakarta EE。 JavaEE是从Java 1.2版本开始推出的Java企业级开发平台&#xff0c;最初的名称是J2EE(J…...

pdf文档动态插入文字水印,45度角,旋转倾斜,位于文档中央,多行水印可插入中文

一行水印 /*** param inputFile 你的PDF文件地址* param outputFile 添加水印后生成PDF存放的地址* param waterMarkName 你的水印* return*/public static boolean waterMark(String inputFile,String outputFile, String waterMarkName){try {PdfReader reader new PdfRead…...

[ 渗透测试面试篇-2 ] 针对大规模资产的攻击思路

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…...

深入解析 Web 应用中的 CHIPS(Partitioned Cookie Attribute)

深入解析 Web 应用中的 CHIPS&#xff08;Partitioned Cookie Attribute&#xff09; 最新发现flask3.1.0 的版本引入了新的特性&#xff1a;对CHIPS的支持。不少同学对这个可能有点陌生&#xff0c;本文带大家了解一下。 为了在隐私保护和功能需求之间取得平衡&#xff0c;Goo…...

从搭建uni-app+vue3工程开始

技术栈 uni-app、vue3、typescript、vite、sass、uview-plus、pinia 一、项目搭建 1、创建以 typescript 开发的工程 npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project2、安装sass npm install -D sass// 安装sass-loader&#xff0c;注意需要版本10&#xff0c;…...

归并排序与逆序对问题(C语言版)

一、引言 归并排序是一种高效且稳定的排序方法&#xff0c;而逆序对问题是算法领域的一个经典问题&#xff0c;本文教大家如何实现归并排序&#xff0c;以及如何使用归并排序去结果逆序对问题 二、归并排序 归并排序思想 分解&#xff1a;将待排序的数组分成两半&#xff0c…...

网络爬虫总结与未来方向

通过深入学习和实际操作&#xff0c;网络爬虫技术从基础到进阶得以系统掌握。本节将全面总结关键内容&#xff0c;并结合前沿技术趋势与最新资料&#xff0c;为开发者提供实用性强的深度思考和方案建议。 1. 网络爬虫技术发展趋势 1.1 趋势一&#xff1a;高性能分布式爬虫 随…...

C++ 核心数据结构:Stack 与 Queue 类深度解析

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 目录 &#x1f4af;前言 &#x1f4af;Stack 类 &#xff08;一&#xff09;Stack 类的概念与特点 &#xff08;二&#x…...

Python枚举类详解:用enum模块高效管理常量数据

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 在编程中,常量的管理是一个关键环节,合理的管理常量可以提高代码的可读性和可维护性。Python的enum模块提供了一种有效的方式来组织常量数据,通过枚举类(Enum)将相关的常量值集合在一起,使代码更具结…...

企业OA管理系统:Spring Boot技术深度探索

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…...

汽车免拆诊断案例 | 2012款路虎揽胜运动版柴油车加速无力

故障现象  一辆2012款路虎揽胜运动版车&#xff0c;搭载3.0T柴油发动机&#xff08;型号为306DT&#xff09;&#xff0c;累计行驶里程约为10.2万km。车主进厂反映&#xff0c;车辆行驶中加速无力&#xff0c;且发动机故障灯异常点亮。 故障诊断 接车后试车&#xff0c;发动…...

uniapp接入高德地图

下面代码兼容安卓APP和H5 高德地图官网&#xff1a;我的应用 | 高德控制台 &#xff0c;绑定服务选择《Web端(JS API)》 /utils/map.js 需要设置你自己的key和安全密钥 export function myAMap() {return new Promise(function(resolve, reject) {if (typeof window.onLoadM…...