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

C++:使用红黑树封装map和set

目录

一. 如何使用一颗红黑树同时实现map和set

二. 红黑树的节点插入操作

三. 红黑树迭代器的实现

3.1 begin()和end()

3.2 operator++和operator--

3.3 红黑树迭代器实现完整版代码

四. map和set的封装

附录:用红黑树封装map和set完整版代码

1. RBTree.h文件

2. map.h文件

3. set.h文件


一. 如何使用一颗红黑树同时实现map和set

我们知道,map和set的底层都是通过红黑树来实现的,它们的不同在于:map存储的是一键值对,键值对的第一个数据用于搜索树的比较,第二个数据用于与之配对,而set则只有一个数据。需要采用模板(泛型编程)的方法来定义红黑树节点,并在map和set中给定红黑树类模板不同的模板参数类型,

图1.1 红黑树节点、红黑树类模板与map和set类模板之间的关系

观察图1.1,我们可以总结出RBTreeNode、RBTree、map和set类模板之间的如下规则:

  • 红黑树节点只有一个模板参数,set有一个模板参数,其本身就是节点的数据类型,map有两个模板参数,分别为创建键值对的first和second数据类型。
  • 在map中,RBTreeNode中的模板参数类型为pair键值对,由于map中要取出键值对的first比较创建搜索树,而直接用>或<对pair比较不符合要求,因此定义仿函数KeyOfV来获取用于比较的数据。

二. 红黑树的节点插入操作

用于对map和set封装的红黑树的查找操作与普通红黑树一致,唯一的不同在于需要创建KeyOfV类的对象,并使用仿函数进行比较。如果希望与库中的insert更加贴合,则应返还键值对pair<iterator, bool>类型数据。

具体的红黑树的插入实现流程,可参考博文:C++数据结构:手撕红黑树_【Shine】光芒的博客-CSDN博客

代码2.1:(红黑树节点插入)

	std::pair<iterator, bool> insert(const T& date){//插入第一个节点if (_root == nullptr){_root = new Node(date);_root->_col = BLACK;   //根节点为黑色return std::make_pair(_root, true);}KeyOfT kov;   //用于筛选比较数据的类对象//寻找节点插入的位置Node* parent = nullptr;   Node* cur = _root;while (cur){//如果cur节点的key值大于插入键值对的key,向左子树查找if (kov(cur->_date) > kov(date)){parent = cur;cur = cur->_left;}else if(kov(cur->_date) < kov(date))  //如果cur节点的key值小于插入键值对的key,向左子树查找{parent = cur;cur = cur->_right;}else  //相等表明节点已存在,插入失败{return std::make_pair(cur, false);}}//判断新节点是parent的左节点还是右节点,链接//默认新插入的节点为红色cur = new Node(date);Node* newNode = cur;cur->_col = RED;cur->_parent = parent;if (kov(parent->_date) > kov(date)){parent->_left = cur;}else{parent->_right = cur;}//如果parent节点不为空且为红色,那么红黑树的结构在插入节点后被破坏,需要调整while (parent && parent->_col == RED){Node* grandParent = parent->_parent;   //祖父节点assert(grandParent);assert(grandParent->_col == BLACK);   //断言检查,如果祖父节点为空或为黑色,那么红黑树结构在节点插入之前就存在问题if (parent == grandParent->_left)  //插入在祖父节点的左子树{Node* uncle = grandParent->_right;//情况一:cur为红,parent为红,grandFather为黑,uncle为红if (uncle && uncle->_col == RED){//将parent节点和uncle节点变为黑,grandFather节点变为红,然后继续向上调整parent->_col = BLACK;uncle->_col = BLACK;grandParent->_col = RED;cur = grandParent;parent = cur->_parent;}	else  //情况二、三:cur为红,parent为红,grandFather为黑,uncle不存在或为黑{if (parent->_left == cur){//情况二 -- 进行右单旋 + 变色(parent变黑,grandFather变红)//    g//  p   u//cRotateR(grandParent);parent->_col = BLACK;grandParent->_col = RED;}else{//情况三 -- 进行左右双旋 + 变色(cur节点变为黑,grandFater节点变为红)//    g//  p   u//   u RotateLR(grandParent);cur->_col = BLACK;grandParent->_col = RED;}break;}}else  //parent == grandParent->_right{Node* uncle = grandParent->_left;  //叔叔节点//情况一:cur为红,parent为红,grandFather为黑,uncle为红if (uncle && uncle->_col == RED){//将parent节点和uncle节点变为黑,grandFather节点变为红,然后继续向上调整parent->_col = BLACK;uncle->_col = BLACK;grandParent->_col = RED;cur = grandParent;parent = cur->_parent;}else{//情况二、三:cur为红,parent为红,grandFather为黑,uncle不存在或为黑if (parent->_right == cur){//情况二 -- 进行右单旋 + 变色(parent变黑,grandFather变红)//   g// u   p//       cRotateL(grandParent);parent->_col = BLACK;grandParent->_col = RED;}else{//情况三 -- 进行右左双旋 + 变色(cur节点变为黑,grandFater节点变为红)//    g// u     p//     cRotateRL(grandParent);cur->_col = BLACK;grandParent->_col = RED;}break;}}}_root->_col = BLACK;   //根节点为黑色return std::make_pair(newNode, true);}

三. 红黑树迭代器的实现

我们要额外封装一个类struct  __RBTree_iterator_来实现红黑树迭代器,这个类有三个模板参数T、Ref、Ptr,这样做的目的是定义一份迭代器类模板就可以实现普通迭代器和const迭代器。

  • typedef __RBTree_iterator_<T, T&, T*> iterator;   //红黑树迭代器

3.1 begin()和end()

STL标准规定迭代器区间begin()和end()为左闭右开区间,而对红黑树遍历获取的数据为升序序列,因此,begin()应该为左下角位置处的节点,end()应该为哨兵卫的头结点_head。这里从便于理解和实现的角度出发,将_head设为nullptr,即:end()返回空指针。

图3.1 红黑树的begin()和end()

代码3.1:(begin和end)

	//获取begin()位置 -- 最左侧节点iterator begin(){Node* left = _root;while (left && left->_left){left = left->_left;}return iterator(left);}iterator end(){return iterator(nullptr);}

3.2 operator++和operator--

operator++就是查找中序遍历的下一个节点,可分为两种情况讨论:

  • 如果节点的右子树不为空,则为右子树最左侧的节点。
  • 如果节点的右子树为空,则向上查找孩子不是父亲的右子节点的那个节点。
图3.2 operator++的两种情况

operator--与operator++正好相反,为找中序遍历的前一个节点,亦可分两种情况讨论:

  • 如果节点的左子树不为空,则为左子树最右侧的节点。
  • 如果节点的左子树为空,则向上查找孩子不是父亲的左子节点的那个节点。
图3.3 operator--的两种情况

代码3.2:(operator++和operator--)

	typedef RBTreeNode<T> Node;    //红黑树节点typedef __RBTree_iterator_<T, Ref, Ptr> Self;	//++运算符重载函数Self& operator++(){if (_node->_right != nullptr){//找右子树的最左侧节点Node* left = _node->_right;while (left->_left){left = left->_left;}_node = left;}else{//找孩子节点为左孩子节点的位置,或者父亲节点为空Node* parent = _node->_parent;Node* cur = _node;while (parent && parent->_right == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}//--运算符重载函数Self& operator--(){if (_node->_left != nullptr){Node* right = _node->_left;while (right->_right){right = right->_right;}_node = right;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && parent->_left == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}

3.3 红黑树迭代器实现完整版代码

//红黑树迭代器模板
template<class T, class Ref, class Ptr>
struct __RBTree_iterator_
{typedef RBTreeNode<T> Node;    //红黑树节点typedef __RBTree_iterator_<T, Ref, Ptr> Self;Node* _node;//构造函数__RBTree_iterator_(Node* node): _node(node){ }//解引用函数Ref operator*(){return _node->_date;}//成员访问操作符->重载Ptr operator->(){return &_node->_date;}bool operator==(const Self& it) const{return _node == it._node;}bool operator!=(const Self& it) const{return _node != it._node;}//++运算符重载函数Self& operator++(){if (_node->_right != nullptr){//找右子树的最左侧节点Node* left = _node->_right;while (left->_left){left = left->_left;}_node = left;}else{//找孩子节点为左孩子节点的位置,或者父亲节点为空Node* parent = _node->_parent;Node* cur = _node;while (parent && parent->_right == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}//--运算符重载函数Self& operator--(){if (_node->_left != nullptr){Node* right = _node->_left;while (right->_right){right = right->_right;}_node = right;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && parent->_left == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
};

四. map和set的封装

map和set底层都是通过红黑树来实现的,只需在map和set中定义一颗红黑树的自定义类型变量,然后调用红黑树的接口函数即可。

这里需要特别注意的是map中的operator[]函数,其实现为先调用insert函数,insert函数返回一个键值对,first为插入的节点或Key与插入节点相等位置的迭代器,second为bool类型变量,用来表示是否有新节点成功插入。函数只需返回insert返回的键值对的second的引用即可。

注意用于提取Key的仿函数要在map和set中分别定义。

代码4.1:(map的封装)

namespace zhang
{template <class K, class V>class map{struct KeyOfV{const K& operator()(const std::pair<K,V>& val){return val.first;}};public:typedef typename RBTree<K, std::pair<K, V>, KeyOfV>::iterator iterator;std::pair<iterator, bool> insert(const std::pair<K, V>& kv){return _t.insert(kv);}iterator begin(){return _t.begin();}iterator end(){return _t.end();}V& operator[](const K& key){std::pair<iterator, bool> ret = insert(std::make_pair(key, V()));return ret.first->second;}private:RBTree<K, std::pair<K,V>, KeyOfV> _t;   //红黑树};
}

代码4.2:(set的模拟实现)

namespace zhang
{template <class K>class set{struct KeyOfV{const K& operator()(const K& val){return val;}};public:typedef typename RBTree<K, K, KeyOfV>::iterator iterator;std::pair<iterator, bool> insert(const K& key){return _t.insert(key);}iterator begin(){return _t.begin();}iterator end(){return _t.end();}K& operator[](const K& key){std::pair<iterator, bool> ret = insert(key);return *ret.first;}private:RBTree<K, K, KeyOfV> _t;   //红黑树};
}

附录:用红黑树封装map和set完整版代码

1. RBTree.h文件

#include<iostream>
#include<assert.h>//枚举常量 -- 红色、黑色
enum Color
{RED,BLACK
};//定义红黑树节点
template<class T>
struct RBTreeNode
{RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _date;  //数据值(set为单个值,map为键值对pair)Color _col;   //节点颜色RBTreeNode(const T& date)   //节点构造函数: _left(nullptr), _right(nullptr), _parent(nullptr), _date(date), _col(RED){ }
};//红黑树迭代器模板
template<class T, class Ref, class Ptr>
struct __RBTree_iterator_
{typedef RBTreeNode<T> Node;    //红黑树节点typedef __RBTree_iterator_<T, Ref, Ptr> Self;Node* _node;//构造函数__RBTree_iterator_(Node* node): _node(node){ }//解引用函数Ref operator*(){return _node->_date;}//成员访问操作符->重载Ptr operator->(){return &_node->_date;}bool operator==(const Self& it) const{return _node == it._node;}bool operator!=(const Self& it) const{return _node != it._node;}//++运算符重载函数Self& operator++(){if (_node->_right != nullptr){//找右子树的最左侧节点Node* left = _node->_right;while (left->_left){left = left->_left;}_node = left;}else{//找孩子节点为左孩子节点的位置,或者父亲节点为空Node* parent = _node->_parent;Node* cur = _node;while (parent && parent->_right == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}//--运算符重载函数Self& operator--(){if (_node->_left != nullptr){Node* right = _node->_left;while (right->_right){right = right->_right;}_node = right;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && parent->_left == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
};//红黑树类模板
template<class K, class T, class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;    //类型重定义红黑树节点public:typedef __RBTree_iterator_<T, T&, T*> iterator;   //迭代器std::pair<iterator, bool> insert(const T& date){//插入第一个节点if (_root == nullptr){_root = new Node(date);_root->_col = BLACK;   //根节点为黑色return std::make_pair(_root, true);}KeyOfT kov;   //用于筛选比较数据的类对象//寻找节点插入的位置Node* parent = nullptr;   Node* cur = _root;while (cur){//如果cur节点的key值大于插入键值对的key,向左子树查找if (kov(cur->_date) > kov(date)){parent = cur;cur = cur->_left;}else if(kov(cur->_date) < kov(date))  //如果cur节点的key值小于插入键值对的key,向左子树查找{parent = cur;cur = cur->_right;}else  //相等表明节点已存在,插入失败{return std::make_pair(cur, false);}}//判断新节点是parent的左节点还是右节点,链接//默认新插入的节点为红色cur = new Node(date);Node* newNode = cur;cur->_col = RED;cur->_parent = parent;if (kov(parent->_date) > kov(date)){parent->_left = cur;}else{parent->_right = cur;}//如果parent节点不为空且为红色,那么红黑树的结构在插入节点后被破坏,需要调整while (parent && parent->_col == RED){Node* grandParent = parent->_parent;   //祖父节点assert(grandParent);assert(grandParent->_col == BLACK);   //断言检查,如果祖父节点为空或为黑色,那么红黑树结构在节点插入之前就存在问题if (parent == grandParent->_left)  //插入在祖父节点的左子树{Node* uncle = grandParent->_right;//情况一:cur为红,parent为红,grandFather为黑,uncle为红if (uncle && uncle->_col == RED){//将parent节点和uncle节点变为黑,grandFather节点变为红,然后继续向上调整parent->_col = BLACK;uncle->_col = BLACK;grandParent->_col = RED;cur = grandParent;parent = cur->_parent;}	else  //情况二、三:cur为红,parent为红,grandFather为黑,uncle不存在或为黑{if (parent->_left == cur){//情况二 -- 进行右单旋 + 变色(parent变黑,grandFather变红)//    g//  p   u//cRotateR(grandParent);parent->_col = BLACK;grandParent->_col = RED;}else{//情况三 -- 进行左右双旋 + 变色(cur节点变为黑,grandFater节点变为红)//    g//  p   u//   u RotateLR(grandParent);cur->_col = BLACK;grandParent->_col = RED;}break;}}else  //parent == grandParent->_right{Node* uncle = grandParent->_left;  //叔叔节点//情况一:cur为红,parent为红,grandFather为黑,uncle为红if (uncle && uncle->_col == RED){//将parent节点和uncle节点变为黑,grandFather节点变为红,然后继续向上调整parent->_col = BLACK;uncle->_col = BLACK;grandParent->_col = RED;cur = grandParent;parent = cur->_parent;}else{//情况二、三:cur为红,parent为红,grandFather为黑,uncle不存在或为黑if (parent->_right == cur){//情况二 -- 进行右单旋 + 变色(parent变黑,grandFather变红)//   g// u   p//       cRotateL(grandParent);parent->_col = BLACK;grandParent->_col = RED;}else{//情况三 -- 进行右左双旋 + 变色(cur节点变为黑,grandFater节点变为红)//    g// u     p//     cRotateRL(grandParent);cur->_col = BLACK;grandParent->_col = RED;}break;}}}_root->_col = BLACK;   //根节点为黑色return std::make_pair(newNode, true);}//中序遍历函数void InOrder(){_InOrder(_root);std::cout << std::endl;}//红黑树检验函数bool IsRBTree(){//空树是合法的红黑树if (_root == nullptr){return true;}//检查根节点颜色if (_root->_col == RED){std::cout << "根节点颜色不是黑色" << std::endl;}int baseBlackNum = 0;   //基准黑色节点个数//以最左侧路径为基准,计算黑色节点个数,每条路径黑色节点数目都应该相同Node* cur = _root;while (cur){if (cur->_col == BLACK){++baseBlackNum;}cur = cur->_left;}bool blackNumTrue = PrevCheck(_root, 0, baseBlackNum);   //检查每条路径黑色节点数目是否相同bool colorTrue = CheckColor(_root);  //检查是否存在连续红色节点return blackNumTrue && colorTrue;}//获取begin()位置 -- 最左侧节点iterator begin(){Node* left = _root;while (left && left->_left){left = left->_left;}return iterator(left);}iterator end(){return iterator(nullptr);}private:bool CheckColor(Node* root){if (root == nullptr){return true;}//如果本节点为红色且父亲节点也为红色,证明存在连续红色节点,结构错误if (root->_col == RED && root->_parent && root->_parent->_col == RED){std::cout << "存在连续的红色节点" << std::endl;return false;}return CheckColor(root->_left) && CheckColor(root->_right);}bool PrevCheck(Node* root, int blackNum, int baseBlackNum){if (root == nullptr){if (blackNum != baseBlackNum){std::cout << "每条路径上黑色节点的数目不同" << std::endl;return false;}else{return true;}}if (root->_col == BLACK){++blackNum;}return PrevCheck(root->_left, blackNum, baseBlackNum)&& PrevCheck(root->_right, blackNum, baseBlackNum);}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);std::cout << root->_kv.first << " ";_InOrder(root->_right);}void RotateR(Node* parent)   //右单旋函数{Node* pNode = parent->_parent;    Node* pL = parent->_left;   //左子节点Node* pLR = pL->_right;   //左子节点的右子节点//将pLR节点托管给parent节点的左子节点parent->_left = pLR;if (pLR != nullptr){pLR->_parent = parent;}//将父亲节点托管给pL节点的右子节点pL->_right = parent;  parent->_parent = pL;//此时这颗进行旋转的子树的根节点变为了pL,pL要与pNode节点连接if (parent == _root){_root = pL;pL->_parent = nullptr;}else{pL->_parent = pNode;if (pNode->_left == parent){pNode->_left = pL;}else{pNode->_right = pL;}}}void RotateL(Node* parent)   //左单旋函数{Node* pNode = parent->_parent;Node* pR = parent->_right;    //右子节点Node* pRL = pR->_left;   //右子节点的左子节点//将pLR节点托管给parent节点的右子节点parent->_right = pRL;if (pRL != nullptr){pRL->_parent = parent;}//将parent节点托管给pR的左子节点pR->_left = parent;parent->_parent = pR;if (_root == parent){_root = pR;_root->_parent = nullptr;}else{pR->_parent = pNode;if (pNode->_left == parent){pNode->_left = pR;}else{pNode->_right = pR;}}}void RotateLR(Node* parent)  //左右双旋函数{RotateL(parent->_left);RotateR(parent);}void RotateRL(Node* parent)  //右左双旋函数{RotateR(parent->_right);RotateL(parent);}private:Node* _root = nullptr;
};

2. map.h文件

#include "RBTree.h"namespace zhang
{template <class K, class V>class map{struct KeyOfV{const K& operator()(const std::pair<K,V>& val){return val.first;}};public:typedef typename RBTree<K, std::pair<K, V>, KeyOfV>::iterator iterator;std::pair<iterator, bool> insert(const std::pair<K, V>& kv){return _t.insert(kv);}iterator begin(){return _t.begin();}iterator end(){return _t.end();}V& operator[](const K& key){std::pair<iterator, bool> ret = insert(std::make_pair(key, V()));return ret.first->second;}private:RBTree<K, std::pair<K,V>, KeyOfV> _t;   //红黑树};
}

3. set.h文件

namespace zhang
{template <class K>class set{struct KeyOfV{const K& operator()(const K& val){return val;}};public:typedef typename RBTree<K, K, KeyOfV>::iterator iterator;std::pair<iterator, bool> insert(const K& key){return _t.insert(key);}iterator begin(){return _t.begin();}iterator end(){return _t.end();}K& operator[](const K& key){std::pair<iterator, bool> ret = insert(key);return *ret.first;}private:RBTree<K, K, KeyOfV> _t;   //红黑树};
}

相关文章:

C++:使用红黑树封装map和set

目录 一. 如何使用一颗红黑树同时实现map和set 二. 红黑树的节点插入操作 三. 红黑树迭代器的实现 3.1 begin()和end() 3.2 operator和operator-- 3.3 红黑树迭代器实现完整版代码 四. map和set的封装 附录&#xff1a;用红黑树封装map和set完整版代码 1. RBTree.h文件…...

Go 命令

目录 文章目录 go buildgo cleango fmtgo getgo installgo testgo toolgo generategodoc其它命令 go build 这个命令主要用于编译代码。在包的编译过程中&#xff0c;若有必要&#xff0c;会同时编译与之相关联的包。 如果是普通包&#xff0c;就像我们在1.2节中编写的mymath包…...

LEO、HW、LSO、LW 分别代表什么?

LEO &#xff1a;是 LogEndOffset 的简称&#xff0c;代表当前日志文件中下一条。HW&#xff1a;水位或水印一词&#xff0c;也可称为高水位 &#xff08;high watermark&#xff09; ,通常被用在流式处理领域 &#xff08;flink、spark&#xff09; &#xff0c;以表征元素…...

问题 B: 跳石头(C++)(二分答案)

目录 1.题目描述 2.AC 1.题目描述 问题 B: 跳石头 时间限制: 1.000 Sec 内存限制: 128 MB提交 状态 题目描述 一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点…...

bugku——变量1

拿到题目后是一串PHP代码&#xff0c;给到提示是flag在变量中&#xff0c;接下来进行代码审计 error_reporting(0)&#xff1a;关闭错误报告 include “flag1.php”:包含flag1.php文件 highlight_file(_file_)&#xff1a;页面进行语法高亮显示 isset($_GET[‘args’])&#xf…...

网络数据包丢失监控

什么是网络数据包 数据包或网络数据包是通过网络传输的小数据单元。顾名思义&#xff0c;这些是小的、离散的数据单元。单独来看&#xff0c;这些单位不一定有多大意义。它们只是正在传输的整体消息的一部分&#xff0c;这些消息已被组装成多个层。但是&#xff0c;当组合在一…...

Linux服务器安装部署MongoDB数据库 - 无公网IP远程连接

目录 前言 1. 配置Mongodb源 2. 安装MongoDB 3. 局域网连接测试 4. 安装cpolar内网穿透 5. 配置公网访问地址 6. 公网远程连接 7. 固定连接公网地址 8. 使用固定地址连接 转载自Cpolar Lisa文章&#xff1a;Linux服务器安装部署MongoDB数据库 - 无公网IP远程连接「内网…...

CSS面试题:30道含答案和代码示例的练习题

什么是 CSS&#xff1f;它的作用是什么&#xff1f; CSS&#xff08;层叠样式表&#xff09;是一种用于描述网页样式的语言。它的作用是控制网页的布局、字体、颜色、背景等方面的样式。如何在 HTML 页面中引入 CSS&#xff1f; 可以使用 标签将 CSS 文件引入到 HTML 页面中。例…...

时间轮的golang实践浅析

引言 下列代码模仿一段RPC请求的执行过程&#xff0c;执行后会有哪些问题&#xff1a; RPC代码示例答案&#xff1a;因为超时控制后未阻断后续请求&#xff0c;导致并发读写产生Panic思考&#xff1a;客户端发起 HTTP 请求后&#xff0c;如果在指定时间内没有收到服务器的响应…...

Linux命令_stress 快速模拟CPU、内存、磁盘消耗

ping的安装命令&#xff1a;apt-get install -y inetutils-ping 会遇到Unable to locate package inetutils-ping问题 正确的操作是&#xff1a; ** 这时候需要敲&#xff1a;apt-get update&#xff0c;这个命令的作用是&#xff1a;同步 /etc/apt/sources.list 和 /etc/apt/…...

可视化绘图技巧100篇分析篇(二)-生存曲线(LM曲线)

目录 前言 几个高频面试题目 roc曲线和生存曲线区别 生存曲线模型 生存曲线组件讲解...

UP主发车啦!撩人仙侠文系列,谁来管管这个反派啊!

本人书龄4年&#xff0c;平时很爱看小说&#xff0c;阅遍无数经典修仙文&#xff0c;熬夜党的最爱啊&#xff01;&#xff01;&#xff01;&#xff01;我心中的仙侠top&#xff0c;都是我的心头爱。 一般我都会跟朋友说这六本五星级仙侠好文&#xff0c;如果她们不看&#xf…...

K8S使用持久化卷存储到NFS(NAS盘)

参考文章&#xff1a;K8S-v1.20中使用PVC持久卷 - 知乎 目录 1、概念&#xff1a; 1.1 基础概念 1.2 PV的配置 1.2.1 静态PV配置 1.2.2 动态PV配置 1.2.3 PVC与PV的绑定 1.2.4 PVC及PV的使用 2 部署PV及PVC 2.1 所有K8S机器都需要安装NFS程序 2.2 仅针对需要暴露文件…...

一图看懂 multidict 模块:类似于字典的键值对集合,键可以多次出现,资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 multidict 模块&#xff1a;类似于字典的键值对集合&#xff0c;键可以多次出现&#xff0c;资料整理笔记&#xff08;大全&#xff09; &#x1f9ca;摘要&#x1f9ca;模…...

django CBV 与 DRF APIView源码分析

django CBV源码分析 在django框架中&#xff0c;视图层中的逻辑即可以使用函数处理也可以使用类进行处理&#xff0c;如果在视图层中使用函数处理请求&#xff0c;就是FBV(function base views)&#xff0c;如果在视图层中使用类处理请求&#xff0c;就是CBV(class base views…...

沃尔玛入驻教程:中国卖家如何免费、快速入驻沃尔玛walmart.com?

作为一家全球知名的零售巨头&#xff0c;沃尔玛&#xff08;Walmart&#xff09;的在线商城walmart.com拥有庞大的消费者基础和巨大的商机。对于中国的卖家来说&#xff0c;入驻沃尔玛的平台是一个很好的机会&#xff0c;但是有没有什么方法可以免费、快速入驻呢&#xff1f;有…...

《花雕学AI》Poe 上的四种 AI 机器人,你该怎么选?ChatGPT、Sage、Claude 和 Dragonfly对比

虽然 ChatGPT 是一项革命性的技术&#xff0c;但它作为一个消费产品却有点失败。你可能会花很长时间等待 OpenAI 的聊天机器人加载&#xff0c;或者根本无法使用它&#xff0c;因为它太大了。就算你能用上它&#xff0c;它也很缓慢&#xff0c;而且它的界面也很丑陋。它甚至没有…...

localStorage

目录 localStorage与sessionStorage localStorage的Set与Get localStorage传递参数 localStorage与sessionStorage 现代浏览器提供了一种被称为"Web Storage APIs"&#xff08;Web 存储接口&#xff09;的机制&#xff0c;允许在同一浏览器的不同标签页之间共享数…...

二十五、SQL 数据分析实战(9个中等难度的SQL题目)

文章目录 题目1: App 使用频率分析题目2: App 下载情况统计题目3: 寻找活跃学习者题目4: 商品分类整理题目5: 商品销售分析题目6: 网约车司机收益统计题目7: 网站登录时间间隔统计题目8: 不同区域商品收入统计题目9: 信贷逾期情况统计 题目1: App 使用频率分析 现有一张用户使…...

JavaSE_02基本语法-编程单词词汇

boolean [bʊlɪən] 变量的基本数据类型之一&#xff1a;布尔型const [kɒnst] n. 常量&#xff0c;常数constant [kɒnst(ə)nt] n. [数] 常数&#xff1b;恒量continue [kən’tɪnjuː] vi. 继续&#xff0c;连续;default [dɪ’fɔːlt; diːfɔːlt] 默认的&#xff0c;缺…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

Qt Quick Controls模块功能及架构

Qt Quick Controls是Qt Quick的一个附加模块&#xff0c;提供了一套用于构建完整用户界面的UI控件。在Qt 6.0中&#xff0c;这个模块经历了重大重构和改进。 一、主要功能和特点 1. 架构重构 完全重写了底层架构&#xff0c;与Qt Quick更紧密集成 移除了对Qt Widgets的依赖&…...