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

C++ | 红黑树

 前言

本篇博客讲解c++中数据结构红黑树,看这篇博客之前请先去看:

C++ | AVL树_c++ avl树能有重复节点吗-CSDN博客

💓 个人主页:普通young man-CSDN博客

⏩ 文章专栏:C++_普通young man的博客-CSDN博客

⏩ 本人giee:   普通小青年 (pu-tong-young-man) - Gitee.com

      若有问题 评论区见📝

🎉欢迎大家点赞👍收藏⭐文章
————————————————


红黑树的概念

        红黑树是一种特殊的二叉搜索树,其每个节点包含一个额外的存储位来表示该节点的颜色,颜色可以是红色黑色。通过施加特定的颜色约束规则于从根到任意叶子节点的所有路径上,红黑树保证了没有一条路径会比其他路径长出两倍以上,从而保持树的整体平衡性。

与AVL树相比,两者都是自平衡二叉搜索树,但它们在实现平衡的方式和效率上有所不同:

  • 红黑树:通过对插入或删除操作后的树结构进行重新着色和旋转操作来维持一种宽松的平衡状态。它确保任何路径上的黑色节点数量相同,并且不允许连续两个红色节点出现。
  • AVL树:对每个节点都维护一个平衡因子(左右子树高度差),并通过旋转操作严格保持这棵树的高度尽可能低,即绝对平衡。

红黑树的规则

  1. 节点颜色每个节点要么是红色,要么是黑色。

  2. 根节点颜色根节点必须是黑色。

  3. 红色节点的子节点如果一个节点是红色,则它的两个子节点都必须是黑色。换句话说,任意路径上不会出现连续的红色节点。

  4. 黑色深度一致对于树中的任意一个节点,从该节点到其可达的任何叶子节点(即NULL或哨兵节点)的所有简单路径上,黑色节点的数量(称为黑色深度)必须相同

了解:

《算法导论》等书籍上补充了⼀条每个叶⼦结点(NIL)都是⿊⾊的规则。他这⾥所指的叶⼦结点 不是传统的意义上的叶⼦结点,⽽是我们说的空结点,有些书籍上也把NIL叫做外部结点。NIL是为了 ⽅便准确的标识出所有路径,《算法导论》在后续讲解实现的细节中也忽略了NIL结点,所以我们知道 ⼀下这个概念即可。

实际编程实现中,这些NIL节点通常被隐式处理或者直接忽略,特别是在高级编程语言中,因为它们通常不显式地表示这些空节点。

结合上面概念,看下方图片:

观看图片的时候看一下这个,避免大家去看平衡因子,可能会觉得是咋保持平衡的,其实就是这个颜色规则来保持平衡


红黑树的效率

如何确保最长路径不超过最短路径的二倍?

这个问题其实就被红黑树的规则给抹杀了,我们可以看一个图:

会发现每条路径的黑节点是相同的,这个我们可以参考红黑树的第四条规则,所以极端场景下,最短路径 就就是全是黑色结点的路径,假设最短路径长度为bh(black height),由规则2和规则3可知,任意⼀条路径不会有连续的红色结点,所以极端场景下,最长的路径就是⼀黑⼀红间隔组成,那么最长路径的长度为2*bh。

综合红黑树的4点规则而言,理论上的全⿊最短路径和⼀黑⼀红的最长路径并不是在每棵红黑树都 存在的。假设任意⼀条从根到NULL结点路径的长度为x,那么bh<=h<=2*bh   

 两种特殊情况:

全是最短路径:

全是最长路径:

通过这些我们就可以看出红黑树的效率:

在红黑树中,假设 N为树中节点的数量,为从根节点到叶节点的最短路径长度。根据红黑树的性质,我们可以得出以下关系:

2^{h - 1}  <= N <  2^{2h - 1}

通过对上述不等式进行推导,可以得出 h = logN 。这意味着在红黑树中,增删查改操作在最坏情况下,即沿着最长路径进行操作时,其时间复杂度为 O(log N) 。因为最长路径长度与最短路径长度 h相关,大致为 2h ,所以时间复杂度为 O(2\log N),简化后仍为 O(log N)

相较于AVL树,红黑树的定义和规则更为抽象。AVL树通过直接控制节点高度差来维持平衡,较为直观。而红黑树则是借助四条颜色约束规则,间接实现了树的近似平衡。尽管二者在效率上处于同一量级,但在插入相同数量节点的情况下,由于红黑树对平衡的控制相对宽松,其旋转次数会更少
 


红黑树实现

红黑树的结构

// 枚举值表⽰颜⾊ 
enum Colour
{RED,BLACK
};
// 这⾥我们默认按key/value结构实现 template<class K, class V>
struct RBTreeNode
{// 这⾥更新控制平衡也要加⼊parent指针 pair<K, V> _kv;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Colour _col;RBTreeNode(const pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr){}
};
template<class K, class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
public:
private:Node* _root = nullptr;
};

红黑树的插入

插入是这棵树的主要核心,因为如果你插入错误就不是红黑树

红黑树插入节点规则及处理流程

在红黑树中插入一个新节点时,需要遵循特定的规则,并根据不同情况进行相应处理,具体步骤如下:

步骤 1:确定新增节点的初始颜色
  • 空树插入:若红黑树为空,将新增节点的颜色设置为黑色。这是因为空树插入黑色节点不会违反红黑树的任何规则。
  • 非空树插入:若红黑树非空,将新增节点的颜色设置为红色。这是为了避免破坏红黑树的规则 4(从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点),因为插入黑色节点很可能会破坏此规则,且该规则相对较难维护。
步骤 2:检查插入后是否违反规则

插入节点后,需要检查是否违反红黑树的规则,主要关注规则 3(每个红色节点的两个子节点都是黑色,即从每个叶子到根的所有路径上不能有两个连续的红色节点)。根据父节点的颜色,分以下两种情况处理:

情况 1:父节点为黑色

若父节点为黑色,插入红色节点后没有违反红黑树的任何规则,插入操作结束。

情况 2:父节点为红色

若父节点为红色,插入红色节点后违反了规则 3。由于红黑树的性质,此时祖父节点(父节点的父节点)必定为黑色(因为不能有两个连续的红色节点)。接下来,需要根据叔叔节点(父节点的兄弟节点)的颜色进行进一步的分类处理:

  • 关键颜色固定:此时新增节点 c 为红色,父节点 p 为红色,祖父节点 g 为黑色,这三个节点的颜色是固定的,处理的关键在于叔叔节点 u 的颜色情况
  • 根据叔叔节点 u 分类处理:后续需要根据叔叔节点 u 的颜色分为几种不同情况分别进行旋转和颜色调整操作,以恢复红黑树的性质。具体的分类及处理方式将根据叔叔节点 u 是红色还是黑色,以及节点的相对位置(如左子树或右子树)来确定。

红黑树插入调整:情况1 - 变色

当在红黑树中插入新节点 c 后,若出现 c 为红色、其父节点 p 为红色、祖父节点 g 为黑色,且叔叔节点 u 存在且为红色的情况,可按以下方式处理:

处理步骤

  1. 颜色调整:将 p和 u 的颜色变为黑色,g  的颜色变为红色。
  2. 持续更新:把  g 当作新的 c ,继续向上进行更新操作。

原理分析

由于 p 和 u 原本为红色,g 为黑色,将p 和 u变为黑色后,g 左子树路径和右子树路径各自增加了一个黑色节点。接着把 g 变为红色,相当于保持了以 g为根的子树中每条路径上黑色节点的数量不变。同时,这一操作解决了 c  和 p 连续为红色节点的问题,避免违反红黑树 “不能有两个连续红色节点” 的规则。

d/e/f代表每条路径拥有hb个⿊⾊结点的⼦树,a/b代表每 条路径拥有hb-1个⿊⾊结点的根为红的⼦树,hb>=0

在分析过程中,分别展示了 hb == 0hb == 1 和 hb == 2 的具体情况组合。当 hb 等于 2 时,组合情况多达上百亿种。这些具体样例的作用是辅助我们理解问题,实际上,无论情况数量有多少、情况本身多么复杂,处理方式都是一致的,即进行变色操作后继续向上处理。因此,我们只需关注抽象图来把握整体处理逻辑即可。

红黑树插入调整:情况2 - 单旋(AVL树)+变色

当在红黑树中插入新节点 c 后,若 c 为红色、其父节点 p 为红色、祖父节点 g 为黑色,且叔叔节点 u 存在且为红色时:

节点情况分析

  • 若 u 不存在,c 一定是新增节点。
  • 若 u 存在且为黑,c 一定不是新增节点,c 之前为黑色,是在 c 的子树中插入新节点后,经过类似情况 1 的变色处理,c 从黑色变为红色更新上来的。

处理必要性

为解决 p 和 c 连续红色节点的问题,p 必须变为黑色。又因为 u 不存在或者为黑色,单纯变色无法解决问题,需要结合旋转和变色操作。

p 是 g 的右子节点,c 是 p 的右子节点(左单旋)

  • 操作步骤:以 g 为旋转点进行左单旋,然后将 p 变为黑色,g 变为红色。
  • 操作效果:旋转和变色后,p 成为这棵子树新的根节点。这保证了子树中黑色节点的数量不变,消除了连续的红色节点。并且,无论 p 的父节点是黑色、红色还是为空,都不会违反红黑树规则,无需再往上更新。
    g              p/ \            / \u   p   -->    g   c\c

p 是 g 的左子节点,c 是 p 的左子节点(右单旋)

  • 操作步骤:以 g 为旋转点进行右单旋,然后将 p 变为黑色,g 变为红色。
  • 操作效果:旋转和变色后,p 成为这棵子树新的根节点。既保证了子树中黑色节点的数量不变,又避免了连续的红色节点。而且,不管 p 的父节点状态如何,都不会违反红黑树规则,无需再往上更新。
    g              p/ \            / \p   u   -->    c   g/
c
红黑树插入调整:情况1 - 双旋(AVL树)+变色

当在红黑树中插入节点后,出现 c 为红色、其父节点 p 为红色、祖父节点 g 为黑色,且叔叔节点 u 不存在或者 u 存在但为黑色的情况,具体分析与处理如下:

节点情况分析

  • u 不存在:此时 c 必定是新增节点。
  • u 存在且为黑c 并非新增节点,此前 c 为黑色。是在 c 的子树中插入节点后,经过类似情况 1(叔叔节点为红色时的变色处理)的操作,c 从黑色变为红色并更新上来。

处理必要性分析

为解决 p 和 c 连续红色节点违反红黑树规则的问题,p 必须变为黑色。由于 u 不存在或者为黑色,单纯的变色操作无法恢复红黑树性质,需要结合旋转与变色操作。

情况一:p 是 g 的左子节点,c 是 p 的右子节点

  • 操作步骤
    1. 以 p 为旋转点进行左单旋。
    2. 接着以 g 为旋转点进行右单旋。
    3. 将 c 变为黑色,g 变为红色。
  • 操作效果:操作完成后,c 成为该子树新的根节点。这样既保证了子树中各路径上黑色节点数量不变,又消除了连续的红色节点。而且,无论 c 的父节点状态(黑色、红色或为空)如何,都不会违反红黑树规则,无需再向上更新。
    g             g            c/ \           / \          / \p   u   -->   c   u  -->   p   g\           /                 / \c         p                 p   u

情况二:p 是 g 的右子节点,c 是 p 的左子节点

  • 操作步骤
    1. 以 p 为旋转点进行右单旋。
    2. 再以 g 为旋转点进行左单旋。
    3. 将 c 变为黑色,g 变为红色。
  • 操作效果:操作结束后,c 成为子树新的根节点。同样保证了子树黑色节点数量不变,避免了连续红色节点的出现。并且,不管 c 的父节点状态怎样,都不违反红黑树规则,无需继续向上处理。
    g             g            c/ \           / \          / \u   p   -->   u   c  -->   g   p/             \        / \c               p      u   p

红黑树的插入代码实现

//红黑树
template<class K, class T>
class Red_BlackTree
{typedef  Red_BlackTree_Node<T>  Node;
public://插入//插入bool insert(const T& kv) {//判空:如果是空根节点就是黑色if (_root == nullptr){_root = new Node(kv);_root->_cr = _black;return true;}Node* parent = nullptr;Node* cur = _root;//不为空就插入红色while (cur){if (cur->_kv.first > kv.first) {parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(kv);cur->_cr = _red;//链接节点if (parent->_kv.first > kv.first){parent->_left = cur;}else if (parent->_kv.first < kv.first) {parent->_right = cur;}//判断三插链当中的_parent指向cur->_parent = parent;//parent是红色插入说明出现连续的红(违反规则)while (parent && parent->_cr == _red){Node* grandfather = parent->_parent;//parent 如果是leftif (parent == grandfather->_left){//   g// p   u//uncle存在且为红Node* uncle = grandfather->_right;if (uncle && uncle->_cr == _red) {uncle->_cr = _black;parent->_cr = _black;grandfather->_cr = _red;//继续向上更新cur = grandfather;parent = cur->_parent;}//uncle不存在或为黑else{if (parent->_left == cur) {Rotati_r(grandfather);parent->_cr = _black;grandfather->_cr = _red;}else{Rotati_LR(grandfather);cur->_cr = _black;grandfather->_cr = _red;}break;}}else{//   g// u   pNode* uncle = grandfather->_left;//uncle存在且为红if (uncle && uncle->_cr == _red) {uncle->_cr = _black;parent->_cr = _black;grandfather->_cr = _red;//继续向上更新cur = grandfather;parent = cur->_parent;}//uncle不存在或为黑else{if (parent->_right == cur) {Rotati_l(grandfather);parent->_cr = _black;grandfather->_cr = _red;}else{Rotati_RL(grandfather);cur->_cr = _black;grandfather->_cr = _red;}break;}}}//更新到最后不管_root是不是红都设置为黑_root->_cr = _black;return true;}//右旋转void Rotati_r(Node* parent) {Node* subL = parent->_left;Node* sublr = subL->_right;//旋转parent->_left = sublr;//判断是否是空,为空不能链接避免野指针if (sublr)sublr->_parent = parent;//存储parent节点方便后续链接Node* Pparent = parent->_parent;subL->_right = parent;parent->_parent = subL;//判断是否是root或则是局部旋转方便链接上下节点if (parent == _root) {_root = subL;subL->_parent = nullptr;}else {if (Pparent->_left == parent) {Pparent->_left = subL;}else if (Pparent->_right == parent){Pparent->_right = subL;}subL->_parent = Pparent;}}//左旋转void Rotati_l(Node* parent) {Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (parentParent == nullptr){_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}}//左右旋void Rotati_LR(Node* parent) {Rotati_l(parent->_left);Rotati_r(parent);}//右左旋void Rotati_RL(Node* parent) {Rotati_r(parent->_right);Rotati_l(parent);}private:Node* _root = nullptr;
};

红黑树的查找

直接看代码吧,这个已经非常简单了,按⼆叉搜索树逻辑实现即可,搜索效率为O(logN)

	Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}else{return cur;}}return nullptr;}

红黑树的验证

在红黑树中,判断其是否符合要求时,直接获取最长路径和最短路径并检查最长路径是否不超过最短路径的 2 倍这种方式不可行。因为即便满足该条件,红黑树仍可能在颜色方面不满足规则,虽然当前可能看似正常,但后续继续插入节点时仍会出现问题。所以,应该检查红黑树的四条基本规则,只要满足这四条规则,就能确保最长路径不超过最短路径的 2 倍。以下是对四条规则检查方法的具体说明:

规则 1:节点颜色类型检查

此x。由于在代码实现中通常会枚举颜色类型,因此在定义节点颜色时就天然保证了该规则的实现,无需额外的检查操作。

规则 2:根节点颜色检查

规则规定根节点必须是黑色。检查时,直接查看红黑树的根节点颜色是否为黑色即可。

规则 3:红色节点子节点颜色检查

规则要求每个红色节点的两个子节点都是黑色。采用前序遍历的方式进行检查,若正向检查红色节点的孩子节点会不太方便,因为孩子节点有两个且不一定都存在。所以,反过来检查每个节点(除根节点外)的父节点颜色更为便捷。若当前节点为红色,而其父节点也为红色,则违反了该规则。

规则 4:各路径黑色节点数量检查

规则要求从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑色节点。同样使用前序遍历,在遍历过程中,利用形参记录从根节点到当前节点的黑色节点数量 blackNum。当前序遍历遇到黑色节点时,blackNum 加 1。当遍历到空节点时,就得到了一条路径上的黑色节点数量。选取任意一条路径的黑色节点数量作为参考值,依次与其他路径的黑色节点数量进行比较,若存在不同,则违反该规则。

// 递归检查红黑树是否满足规则 3(不存在连续红色节点)和规则 4(每条路径上黑色节点数量相同)
// root: 当前递归检查的子树的根节点
// blackNum: 从根节点到当前节点路径上的黑色节点数量
// refNum: 作为参考的一条路径上的黑色节点数量
bool Check(Node* root, int blackNum, const int refNum)
{// 当前节点为空,说明已经遍历完一条路径if (root == nullptr){// 前序遍历⾛到空时,意味着⼀条路径⾛完了 // 比较当前路径的黑色节点数量和参考值if (refNum != blackNum){// 若不相等,输出提示信息,说明存在黑色节点数量不相等的路径cout << "存在⿊⾊结点的数量不相等的路径" << endl;return false;}// 若相等,说明当前路径满足规则 4return true;}// 检查规则 3,即是否存在连续的红色节点// 检查孩⼦不太⽅便,因为孩⼦有两个,且不⼀定存在,反过来检查⽗亲就⽅便多了 // 若当前节点为红色且其父节点也为红色,违反规则 3if (root->_col == RED && root->_parent->_col == RED){// 输出提示信息,指出哪个节点存在连续红色节点cout << root->_kv.first << "存在连续的红⾊结点" << endl;return false;}// 若当前节点为黑色,更新从根节点到当前节点路径上的黑色节点数量if (root->_col == BLACK){blackNum++;}// 递归检查左子树和右子树// 只有当左子树和右子树都满足规则时,整个子树才满足规则return Check(root->_left, blackNum, refNum)&& Check(root->_right, blackNum, refNum);
}// 判断红黑树是否平衡(即是否满足红黑树的所有规则)
bool IsBalance()
{// 若根节点为空,空树被认为是平衡的红黑树if (_root == nullptr)return true;// 规则 2:根节点必须为黑色,若根节点为红色,不满足红黑树规则if (_root->_col == RED)return false;// 计算参考值,即从根节点到其最左子节点路径上的黑色节点数量// 参考值 int refNum = 0;Node* cur = _root;// 沿着左子树向下遍历while (cur){// 若当前节点为黑色,参考值加 1if (cur->_col == BLACK){++refNum;}cur = cur->_left;}// 调用 Check 函数开始递归检查整棵树return Check(_root, 0, refNum);
}

递归展开图:

相关文章:

C++ | 红黑树

前言 本篇博客讲解c中数据结构红黑树&#xff0c;看这篇博客之前请先去看&#xff1a; C | AVL树_c avl树能有重复节点吗-CSDN博客 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青…...

使用Ollama 在Ubuntu运行deepseek大模型:以DeepSeek-coder为例

DeepSeek大模型这几天冲上热搜啦&#xff01; 咱们来亲身感受下DeepSeek模型的魅力吧&#xff01; 整个操作流程非常简单方便&#xff0c;只需要2步&#xff0c;先安装Ollama&#xff0c;然后执行大模型即可。 安装Ollama 在Ubuntu下安装Ollama非常简单&#xff0c;直接sna…...

詳細講一下RN(React Native)中的列表組件FlatList和SectionList

1. FlatList 基礎使用 import React from react; import { View, Text, FlatList, StyleSheet } from react-native;export const SimpleListDemo: React.FC () > {// 1. 準備數據const data [{ id: 1, title: 項目 1 },{ id: 2, title: 項目 2 },{ id: 3, title: 項目 3…...

《深度揭秘:TPU张量计算架构如何重塑深度学习运算》

在深度学习领域&#xff0c;计算性能始终是推动技术发展的关键因素。从传统CPU到GPU&#xff0c;再到如今大放异彩的TPU&#xff08;张量处理单元&#xff09;&#xff0c;每一次硬件架构的革新都为深度学习带来了质的飞跃。今天&#xff0c;就让我们深入探讨TPU的张量计算架构…...

QT使用eigen

QT使用eigen 1. 下载eigen https://eigen.tuxfamily.org/index.php?titleMain_Page#Download 下载后解压 2. QT引入eigen eigen源码好像只有头文件&#xff0c;因此只需要引入头文件就好了 qt新建项目后。修改pro文件. INCLUDEPATH E:\222078\qt\eigen-3.4.0\eigen-3.…...

工业“MCU+AI”

随着工业4.0的推进&#xff0c;传统工业设备正向智能化和自动化方向转型。这要求设备具备更高的算力、更强的实时处理能力以及支持AI算法的能力&#xff0c;以应对工业机器人、电机控制、预测性维护等复杂应用场景。 近年来越来越多的芯片厂商纷纷推出工业“MCUAI”产品&#…...

【Linux】Linux C判断两个IPv6地址是否有包含关系

功能说明 要判断两个 IPv6 地址是否具有包含关系&#xff0c;包括前缀的比较&#xff0c;可以通过以下步骤实现&#xff1a; 解析 IPv6 地址和前缀&#xff1a;将两个 IPv6 地址和它们的前缀长度解析为二进制形式。生成掩码&#xff1a;根据前缀长度生成掩码。按位比较&#…...

多模态论文笔记——TECO

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细解读多模态论文TECO&#xff08;Temporally Consistent Transformer&#xff09;&#xff0c;即时间一致变换器&#xff0c;是一种用于视频生成的创新模型&…...

AI学习(vscode+deepseek+cline)

1、网页生成不成功时&#xff0c;直接根据提示让模型替你解决问题 2、http://localhost:3000 拒绝链接时&#xff0c;cmd输入命令InetMgr&#xff0c;网站右键新建-配置你的网页代码物理地址&#xff0c;这里我还输入本机登录名及密码了&#xff0c;并把端口地址由默认80修改为…...

物业软件推动物业行业数字化转型 实现高效管理和优质客户体验

内容概要 在当今高速发展的数字化时代&#xff0c;物业软件的出现不仅使物业管理变得更加高效&#xff0c;也为行业转型提供了强大的支持。通过整合多种功能&#xff0c;物业软件显著提升了管理效率和客户体验。例如&#xff0c;在线收费和停车管理功能&#xff0c;让业主享受…...

WGCLOUD使用手册 - 登录验证码如何设置

登录页面默认是不用输入验证码的&#xff0c;但是我们也可以根据自己的实际场景&#xff0c;配置登录页面显示验证码&#xff0c;要求用户输入 提示&#xff1a;您需要需要升级到v3.5.3或以上版本&#xff0c;才可以支持此功能 我们在server配置文件里找到配置项vercodeCheck&…...

C# 9.0记录类型:解锁开发效率的魔法密码

一、引言&#xff1a;记录类型的神奇登场 在 C# 的编程世界中&#xff0c;数据结构就像是构建软件大厦的基石&#xff0c;其重要性不言而喻。然而&#xff0c;传统的数据结构定义方式&#xff0c;尤其是在处理简单的数据承载对象时&#xff0c;常常显得繁琐复杂。例如&#xf…...

Python 函数魔法书:基础、范例、避坑、测验与项目实战

Python 函数魔法书&#xff1a;基础、范例、避坑、测验与项目实战 内容简介 本系列文章是为 Python3 学习者精心设计的一套全面、实用的学习指南&#xff0c;旨在帮助读者从基础入门到项目实战&#xff0c;全面提升编程能力。文章结构由 5 个版块组成&#xff0c;内容层层递进…...

Unbutu虚拟机+eclipse+CDT编译调试环境搭建

问题1: 安装CDT&#xff0c;直接Help->eclipse Market space-> 搜cdt , install&#xff0c;等待重启即可. 问题2&#xff1a;C变量不识别vector ’could not be resolved 这是库的头文件没加好&#xff0c;右键Properties->C Build->Enviroment&#xff0c;增加…...

项目部署(springboot项目)

1、安装Nginx&#xff0c;并开启 2、前端项目打包&#xff1a;npm run build:prod--->dist 3、后端项目打包&#xff1a;install--->xxx.jar 4、开放需要的端口号&#xff1a;比如我的后端项目端口号为8282&#xff0c;则需要防火墙和服务器同时开发8282端口 5、将di…...

Spring MVC拦截器

文章目录 1. 拦截器(interceptor)的作用2. 拦截器和过滤器区别3. 拦截器是快速入门 1. 拦截器(interceptor)的作用 Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter&#xff0c;用于对处理器进行预处理和后处理。 将拦截器按一定的顺序联结成一条链&#xff0c;这条…...

Nginx 路由匹配(Nginx Route Matching)

从小白到高手&#xff1a;深入Nginx 路由匹配 在现代互联网应用中&#xff0c;Nginx 作为一款高性能的 Web 服务器&#xff0c;因其灵活性和高效性而广泛应用于各类网站和服务。Nginx 的路由匹配规则是其核心功能之一&#xff0c;负责决定如何处理传入的请求。通过这些规则&am…...

基于RIP的MGRE实验

实验拓扑 实验要求 按照图示配置IP地址配置静态路由协议&#xff0c;搞通公网配置MGRE VPNNHRP的配置配置RIP路由协议来传递两端私网路由测试全网通 实验配置 1、配置IP地址 [R1]int g0/0/0 [R1-GigabitEthernet0/0/0]ip add 15.0.0.1 24 [R1]int LoopBack 0 [R1-LoopBack0]i…...

Spring Boot 中的事件发布与监听:深入理解 ApplicationEventPublisher(附Demo)

目录 前言1. 基本知识2. Demo3. 实战代码 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 基本的Java知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&am…...

【Java基础-41.5】深入解析Java异常链:构建清晰的错误追踪体系

在Java编程中&#xff0c;异常处理是保证程序健壮性和可维护性的重要部分。然而&#xff0c;在实际开发中&#xff0c;异常往往不是孤立发生的&#xff0c;而是由一系列相关的异常引发的。为了更好地理解和处理这种复杂的异常场景&#xff0c;Java引入了 异常链&#xff08;Exc…...

STM32使用VScode开发

文章目录 Makefile形式创建项目新建stm项目下载stm32cubemx新建项目IED makefile保存到本地arm gcc是编译的工具链G++配置编译Cmake +vscode +MSYS2方式bilibiliMSYS2 统一环境配置mingw32-make -> makewindows环境变量Cmake CmakeListnijia 编译输出elfCMAKE_GENERATOR查询…...

特权模式docker逃逸

目录 1.环境 2.上线哥斯拉 3.特权模式逃逸 1.判断是否为docker环境 2.判断是否为特权模式 3.挂载宿主机磁盘到docker 4.计划任务反弹shell 1.环境 ubuntu部署一个存在CVE-2017-12615的docker: (ip:192.168.117.147) kali(ip:192.168.117.128) 哥斯拉 2.上线哥斯拉…...

装出字符串中国第一个匹配项的下标

hello 大家好&#xff01;今天开写一个新章节&#xff0c;每一天一道算法题。让我们一起来学习算法思维吧&#xff01; function strStr(haystack, needle) {return haystack.indexOf(needle); }// 测试示例 const haystack "sadbutsad"; const needle "sad&q…...

从腾讯云数据仓库TCHouse安全地转移数据到AWS Redshift

实现从AWS Direct Connect连接到腾讯云数据仓库TCHouse-P、TCHouse-C或TCHouse-D&#xff0c;然后使用AWS Glue读取数据并在AWS Redshift中创建对应表并复制数据&#xff0c;需要按照以下步骤进行操作&#xff1a; 网络连接设置 AWS Direct Connect配置&#xff1a; 在AWS管理…...

DataComp:探索下一代多模态数据集

目录 一、TL;DR 二、方法 2.1 为什么要单独研究数据质量&#xff1f; 2.2 数据质量的研究范式 三、其他的工作&#xff08;related work&#xff09; 3.1 传统的做法 3.2 数据剪枝和去重&#xff08;paper直接翻译&#xff09; 四、DataComp的benchmark 4.1 竞赛条件限…...

【linux】Linux 常见目录特性、权限和功能

目录特性默认权限主要功能/用途/根目录&#xff0c;所有目录的起点755文件系统的顶层目录&#xff0c;包含所有其他子目录和文件/bin基础二进制命令目录&#xff08;系统启动和修复必需的命令&#xff09;755存放所有用户可用的基本命令&#xff08;如 ls, cp, bash 等&#xf…...

基于SpringBoot电脑组装系统平台系统功能实现六

一、前言介绍&#xff1a; 1.1 项目摘要 随着科技的进步&#xff0c;计算机硬件技术日新月异&#xff0c;包括处理器&#xff08;CPU&#xff09;、主板、内存、显卡等关键部件的性能不断提升&#xff0c;为电脑组装提供了更多的选择和可能性。不同的硬件组合可以构建出不同类…...

Direct2D 极速教程(1) —— 画图形

极速导航 Direct2D 简介创建新项目&#xff1a;001-DrawGraphics弄一个白窗口在窗口上画图 Direct2D 简介 大家在学 WINAPI 的时候的时候有没有想过&#xff0c;怎么在一副窗口上画图呢&#xff1f;大家知道 Windows 系统是 GUI 图形用户界面 系统&#xff0c;以 Graphics 图形…...

DF 开发1

https://www.bilibili.com/video/BV1RFChYxEhJ/ 多个 workspace 图片上传 S3 上传大量文档 https://www.bilibili.com/video/BV1ySsEeUE6i 解决方案 返回 metadata https://www.bilibili.com/video/BV1t3e5eaENo 给出内容引用出处 模型负载均衡 可以以 ollama 在不同端口起服…...

[Computer Vision]实验二:图像特征点提取

目录 一、实验内容 二、实验过程及结果 2.1 Harris角点检测 2.2 SIFT算法 三、实验小结 一、实验内容 采用Harris与SIFT分别提取特征点及对应的描述子&#xff0c;对比两者的区别&#xff08;特征点数量、分布、描述子维度、图像变化对二者的影响等&#xff09;利用特征匹…...

在做题中学习(82):最小覆盖子串

解法&#xff1a;同向双指针——>滑动窗口 思路&#xff1a;题目要求找到s里包含t所有字符的最小子串&#xff0c;这就需要记录在s中每次查找并扩大范围时所包含进去的字符种类是否和t的相同&#xff0c;并且&#xff1a;题目提示t中会有重复字符&#xff0c;因此不能简单认…...

< OS 有关> BaiduPCS-Go 程序的 菜单脚本 Script: BaiduPCS-Go.Menu.sh (bdgo.sh)

目标&#xff1a; 使用 日本阿里云的 VPM 传输文件。 暂时方案&#xff1a; 使用 主机JPN 下载 https://huggingface.co/ 上模型从 JPN 放到 度狗上在家里从狗度下载 为了减少编程&#xff0c;尽量使用现在软件 &#xff0c;就找到 GitHub - qjfoidnh/BaiduPCS-Go: iikira…...

redis缓存和springboot缓存包冲突怎么办

如果Redis缓存与Spring Boot缓存包发生冲突&#xff0c;可以采取以下几种解决方案&#xff1a; 排除Spring Boot缓存包&#xff1a;在pom.xml文件中排除Spring Boot的缓存依赖&#xff0c;以避免与Redis缓存冲突。例如&#xff1a; <dependency><groupId>org.spr…...

云计算技术深度解析与代码使用案例

云计算技术深度解析与代码使用案例 引言 随着信息技术的飞速发展,云计算作为一种革命性的技术,正在逐步改变我们的生活和工作方式。云计算不仅提供了前所未有的计算能力和存储资源,还以其灵活性和可扩展性,成为现代企业数字化转型的重要支撑。本文将深入探讨云计算的核心…...

【教学类-89-01】20250127新年篇01—— 蛇年红包(WORD模版)

祈愿在2025蛇年里&#xff0c; 伟大的祖国风调雨顺、国泰民安、每个人齐心协力&#xff0c;共同经历这百年未有之大变局时代&#xff08;国际政治、AI技术……&#xff09; 祝福亲友同事孩子们平安健康&#xff08;安全、安全、安全&#xff09;、巳巳如意&#xff01; 背景需…...

React Router v6配置路由守卫

首先准备好以下页面 登录页&#xff1a;用户可以在此页面登录。 受保护页&#xff1a;只有登录的用户可以访问&#xff0c;否则会重定向到登录页。 公共页面&#xff1a;不需要鉴权&#xff0c;任何人都可以访问。 1. 安装依赖 首先&#xff0c;我们需要安装 react-router-do…...

双层Git管理项目,github托管显示正常

双层Git管理项目&#xff0c;github托管显示正常 背景 在写React项目时&#xff0c;使用Next.js,该项目默认由git托管。但是我有在项目代码外层记笔记的习惯&#xff0c;我就在外层使用了git托管。 目录如下 code 层内也有.git 文件&#xff0c;对其托管。 我没太在意&…...

Linux--权限

Linux系统的权限管理是保障系统安全的重要机制&#xff0c;以下详细讲解权限相关概念及操作指令&#xff1a; 一、基础权限机制 1. 权限的三元组&#xff0c;读&#xff08;r&#xff09;、写&#xff08;w&#xff09;、执行&#xff08;x&#xff09; 每个文件或目录有三组…...

第25章 项目启航前的密谈

在那弥漫着严谨与专注气息的会议室里&#xff0c;苏睿所长端坐在会议桌前&#xff0c;宛如一座沉稳的山峰&#xff0c;散发着一种让人安心的力量。他的神情认真而庄重&#xff0c;目光中透着几分感慨&#xff0c;仿佛在时光的长河中回溯着项目的点点滴滴。微微侧身看向东方艾艾…...

ModernBERT 为我们带来了哪些启示?

当谷歌在 2018 年推出 BERT 模型时&#xff0c;恐怕没有料到这个 3.4 亿参数的模型会成为自然语言处理领域的奠基之作。 六年后的今天&#xff0c;面对动辄千亿参数的大语言模型浪潮&#xff0c;Answer.AI、LightOn与 HuggingFace 联手打造的 ModernBERT 却选择了一条返璞归真的…...

【MySQL】--- 复合查询 内外连接

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; MySQL &#x1f3e0; 基本查询回顾 假设有以下表结构&#xff1a; 查询工资高于500或岗位为MANAGER的雇员&#xff0c;同时还要满足他们的姓名首字母为…...

Android Studio打包APK

1.导出APK安装包 如果是首次打包&#xff0c;Create new 单击蓝色对话框右边文件夹&#x1f4c2;图标 &#xff0c;选择密钥保存路径&#xff0c;然后在下方File name对话框中填写您想要名称&#xff0c;再点击OK回到密钥创建对话框。 在此对话框中填写密码&#xff08;Passwo…...

RKNN_C++版本-YOLOV5

1.背景 为了实现低延时&#xff0c;所以开始看看C版本的rknn的使用&#xff0c;确实有不足的地方&#xff0c;请指正&#xff08;代码借鉴了rk官方的仓库文件&#xff09;。 2.基本的操作流程 1.读取模型初始化 // 设置基本信息 // 在postprocess.h文件中定义&#xff0c;详见…...

Git常用命令集合

见过不少人、经过不少事、也吃过不少苦&#xff0c;感悟世事无常、人心多变&#xff0c;靠着回忆将往事串珠成链&#xff0c;聊聊感情、谈谈发展&#xff0c;我慢慢写、你一点一点看...... git init <directory》初始化本地仓库 git add <file> 添加文件到暂存区 git …...

【deepseek】deepseek-r1本地部署-第一步:下载LM Studio

要下载LM Studio&#xff0c;可以按照以下步骤进行&#xff1a; 一、访问LM Studio官方网站 打开必应&#xff08;注意&#xff01;百度无法打开官网&#xff09;&#xff0c;输入LM Studio的官方网址&#xff1a;LM Studio - Discover, download, and run local LLMs。进入L…...

【数据结构】_链表经典算法OJ:合并两个有序数组

目录 1. 题目描述及链接 2. 解题思路 3. 程序 3.1 第一版 3.2 第二版 1. 题目描述及链接 题目链接&#xff1a;21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。 新链表是通过拼接给…...

mybatis(78/134)

前天学了很多&#xff0c;关于java的反射机制&#xff0c;其实跳过了new对象&#xff0c;然后底层生成了字节码&#xff0c;创建了对应的编码。手搓了一遍源码&#xff0c;还是比较复杂的。 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE …...

【物联网】ARM核常用指令(详解):数据传送、计算、位运算、比较、跳转、内存访问、CPSR/SPSR、流水线及伪指令

文章目录 指令格式&#xff08;重点&#xff09;1. 立即数2. 寄存器位移 一、数据传送指令1. MOV指令2. MVN指令3. LDR指令 二、数据计算指令1. ADD指令1. SUB指令1. MUL指令 三、位运算指令1. AND指令2. ORR指令3. EOR指令4. BIC指令 四、比较指令五、跳转指令1. B/BL指令2. l…...

Mybatis配置文件详解

MyBatis通过XML或注解的方式将Java对象与数据库中的记录进行映射&#xff0c;极大地简化了数据访问层的开发。而在MyBatis的核心组成部分中&#xff0c;配置文件扮演着举足轻重的角色。它不仅定义了MyBatis的运行环境&#xff0c;还配置了数据源、事务管理、映射器等关键元素&a…...

一组开源、免费、Metro风格的 WPF UI 控件库

前言 今天大姚给大家分享一个开源、免费、Metro风格的 WPF UI 控件库&#xff1a;MahApps.Metro。 项目介绍 MahApps.Metro 是一个开源、免费、Metro风格的 WPF UI 控件库&#xff0c;提供了现代化、平滑和美观的控件和样式&#xff0c;帮助开发人员轻松创建具有现代感的 Win…...