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

高阶数据结构——红黑树实现

目录

1.红黑树的概念

1.1 红黑树的规则:

1.2 红黑树的效率

2.红黑树的实现

2.1 红黑树的结构

2.2 红黑树的插入

2.2.1 不旋转只变色(无论c是p的左还是右,p是g的左还是右,都是一样的变色处理方式)

2.2.2 单旋+变色

2.2.3 双旋+变色

2.2.4 插入代码+总结:

2.3 红黑树的查找

2.4 红黑树的验证


1.红黑树的概念

咱们之前已经学过AVL树了,其实红黑树是一种能够控制平衡的二叉搜索树。咱们之前学习的AVL树,也是一种控制平衡的二叉搜索树,但是,AVL树,是通过平衡因子这个风向标来判断需不需要进行控制平衡,所以,AVL树的平衡很严格。但是红黑树就不一样了,红黑树有它的平衡判断原则,但是,这个的平衡的条件肯定比AVL树要松一些。可以想象为,AVL是一根绷紧的弦线,但是红黑树是一根比较松散的弦线。

红黑树是⼀棵二叉搜索树,他的每个结点增加⼀个存储位来表示结点的颜色,可以是红色或者黑色。 通过对任何⼀条从根到叶子的路径上各个结点的颜色进行约束,红黑树确保没有⼀条路径会比其他路 径长出2倍,因而是接近平衡的。

1.1 红黑树的规则:

那么咱们是如何判断一个树是红黑树的呢?

1. 每个结点不是红色就是黑色。

2. 根结点是黑色的。

3. 如果⼀个结点是红色的,则它的两个孩⼦结点必须是黑色的,也就是说任意⼀条路径不会有连续的 红色结点。(但是可以有连续的两个黑色节点)

4. 对于任意⼀个结点,从该结点到其所有NULL结点的简单路径上,均包含相同数量的黑色结点。

只要控制住了这四点规则,也就控制住了最长路径<=2*最短路径,也就控制住了红黑树的平衡

这里讲一下路径的问题:

请问这个红黑树有几条路径呢?

大家会不会说是2条?啊,恭喜大家,答错了。这里的路径是一定要把下面的空节点也给算上的!

而有些书上为了好让大家区分,就定义了一个NIL的黑色节点,这个其实就是代替了空节点,只不过更好数了而已。

并且,某一条路径上面,节点有几个,那么这条路径的长度就是几。

所以,这个红黑树是不是有6个路径啊!

那么,还是这个图,再来看一个问题:最短路径是多少?最长路径是多少?最短路径是2(18-10),最长路径是3 (18-30-40)。所以,咱们可以发现:

1.最短路径全是黑色节点。

2.最长路径一定小于等于最短路径的2倍。(当然在这幅图中,最长路径是小于最短路径的2倍的)。但是有一种极端的情况,他俩会相等。咱们待会说。

【1】关于上面的1.,如果一条路径全是黑色节点,那么这个路径一定是最短路径。但是,最短路径不一定是全黑节点。

所以,他俩的关系是这种。

【2】关于第二点:

 

• 由规则4可知,从根到NULL结点的每条路径都有相同数量的黑色结点,所以极端场景下,最短路径 就就是全是黑色结点的路径,假设最短路径长度为bh(blackheight)。

• 由规则2和规则3可知,任意⼀条路径不会有连续的红色结点,所以极端场景下,最长的路径就是⼀ 黑⼀红间隔组成,那么最长路径的长度为2*bh。

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

1.2 红黑树的效率

假设N是红黑树树中结点数量,h最短路径的长度,那么2h-1<=N<=2²*h-1,由此推出h ≈logN,也就是意味着红黑树增删查改最坏也就是走最长路径2 *logN,那么时间复杂度还是O(logN)。

红黑树的表达相对AVL树要抽象⼀些,AVL树通过高度差直观的控制了平衡。红黑树通过4条规则的颜 色约束,间接的实现了近似平衡,他们效率都是同⼀档次,但是相对而言,插⼊相同数量的结点,红 黑树的旋转次数是更少的,因为他对平衡的控制没那么严格。

2.红黑树的实现

2.1 红黑树的结构

 // 枚举值表⽰颜⾊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;};

来看一下红黑的大体的代码逻辑,这里与前面AVL树大体不同的是:这里没有了平衡因子bf了,取而代之的是颜色Colour,并且,枚举出两个颜色。

2.2 红黑树的插入

1. 插入⼀个值按二叉搜索树规则进行插入,插入后我们只需要观察是否符合红黑树的4条规则。

2. 如果是空树插入,新增结点是黑色结点。如果是非空树插入,新增结点必须红色结点,因为非空树 插入,新增黑色结点就破坏了规则4,规则4是很难维护的。

3. 非空树插入后,新增结点必须红色结点,如果父亲结点是黑色的,则没有违反任何规则,插入结束

4. 非空树插入后,新增结点必须红色结点,如果父亲结点是红色的,则违反规则3。进⼀步分析,c是 红色,p为红,g必为黑,这三个颜色都固定了(这句话很关键),关键的变化看u的情况,需要根据u分为以下几种 情况分别处理。

总的来说,插入黑色需要维护每条路径上的黑色节点数量,成本很大,所以插入红色节点。

说明:下图中假设我们把新增结点标识为c(cur),c的父亲标识为p(parent),p的父亲标识为 g(grandfather),p的兄弟标识为u(uncle)。

2.2.1 不旋转只变色(无论c是p的左还是右,p是g的左还是右,都是一样的变色处理方式)

c为红,p为红,g为黑,u存在且为红,则将p和u变黑,g变红。在把g当做新的c,继续往上更新。

分析:因为p和u都是红色,g是黑色,把p和u变黑,左边子树路径各增加⼀个黑色结点,g再变红,相 当于保持g所在子树的黑色结点的数量不变,同时解决了c和p连续红色结点的问题,需要继续往上更新 是因为,g是红色,如果g的父亲还是红色,那么就还需要继续处理(因为不可以有连续的两个红色节点)如果g的父亲是黑色,则处理结束 了;如果g就是整棵树的根,再把g变回黑色。

咱们先来看一种简单的情况:

上图就是简单的变色不需要旋转 。

来看这种情况的抽象图:

这是抽象图:这里c只能是原来就存在的节点,a,b,d,e,f均为抽象表示,说明其中还有节点是不固定的。所以这里的c不是新增,这样就可以与下面的节点圆一下,使得各个路径的黑色节点数量一致。但是若是c为新增,那么c下面的a,b可就啥都没了,那么这样的话,各个路径的黑色节点很难控制一致。

所以,这里的c为红色节点,是因为,你插入的时候,插入在了c的其中一个孩子节点的下面,再通过只变色不旋转的情况,使得c变成了红色节点。

【1】h==0

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

这里,c就一定是新增的节点了。如果这里c不是新增,那么要保持各个路径的黑色节点一致,很明显,如果,这儿为黑,不可以,因为右边路径的黑色节点只有一个。为红,也不可以,因为不能有连续的两个红色节点。

【2】h==1

【3】h==2

以上分别展示了hb==0/hb==1/hb==2的具体情况组合分析,当hb等于2时,这里组合 情况上百亿种,这些样例是帮助我们理解,不论情况多少种,多么复杂,处理方式⼀样的,变色再 继续往上处理即可,所以我们只需要看抽象图即可。

所以,殊途同归,这种情况的处理方式都是一样的,所以,不需要过多的关注底层,多看看上面,即可判断出该用什么方法。 

这里还是要提一嘴,不管c位于p的左还是右,p位于g的左还是右,处理方式都是一样的。但是这个只限于uncle存在且为红的情况。因为后面,这些不同,他们的处理方式是不同的。

2.2.2 单旋+变色

c为红,p为红,g为黑,u不存在或者u存在且为黑,u不存在,则c⼀定是新增结点,u存在且为黑,则 c⼀定不是新增,c之前是黑色的,是在c的子树中插入,符合情况1,变色将c从黑色变成红色,更新上 来的。(原因同上)

之前,uncle存在且为红是一种情况,且只有一种处理方式,但是这种uncle不存在或者uncle存在且为黑,是一种情况,这种情况会由于c,p的位置的不同而产生不同的解决办法,在这里,咱们先介绍单旋+变色,最后总结的时候再来总结其他的方法。

分析:p必须变黑,才能解决,连续红色结点的问题,u不存在或者是黑色的,这里单纯的变色无法解 决问题,需要旋转+变色。 

看这个形态,像不像右单旋的形态呢?没错,很像,没错,这里的解决办法就是右单旋。

如果p是g的左,c是p的左,那么以g为旋转点进行右单旋,再把p变黑,g变红即可。p变成课这颗树新 的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为p的父亲是黑色还是红色或者空都不违反规则。(上面是黑节点,可以有两个连续的黑节点,上面是红节点,黑红相接,没有任何问题。)

这个形态像不像左单旋的形态模型,没错,很像,所以用左单旋来解决。 

如果p是g的右,c是p的右,那么以g为旋转点进行左单旋,再把p变黑,g变红即可。p变成课这颗树新 的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为p的父亲是黑色还是红色或者空都不违反规则。 

看这个,uncle不存在的情况,如果只用单个的变色,无法解决问题,因为变色变到最后,根节点成红色的了。

来看uncle存在且为黑的抽象图:

hb==1:
也是一样,不需要太去关注底层的节点有多复杂啥的,多看看上面的形态是啥样的。

2.2.3 双旋+变色

c为红,p为红,g为黑,u不存在或者u存在且为黑,u不存在,则c⼀定是新增结点,u存在且为黑,则 c⼀定不是新增,c之前是黑色的,是在c的子树中插入,符合情况1,变色将c从黑色变成红色,更新上 来的。

 

这个看着像不像咱们的那个先左后右双旋?没错,这个也是同样的解决办法:

如果p是g的左,c是p的右,那么先以p为旋转点进行左单旋,再以g为旋转点进行右单旋,再把c变 黑,g变红即可。c变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且 不需要往上更新,因为c的色亲是黑色还是红色或者空都不违反规则。 

这个像咱们的先右后左双旋转模型,没错,这个的处理方法也是这种:

如果p是g的右,c是p的左,那么先以p为旋转点进行右单旋,再以g为旋转点进行左单旋,再把c变 黑,g变红即可。c变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且 不需要往上更新,因为c的父亲是黑色还是红色或者空都不违反规则 。

2.2.4 插入代码+总结:

OK,那么接下来来看关键的代码:

//插入
bool Insert(const pair<k, v>& kv)
{if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;//别忘了根节点必须是黑色的return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else if (kv.first < cur->_kv.first){parent = cur;cur = cur->_left;}else{return false;//这个是return false,不是assert(false)}}//插入红节点cur = new Node(kv);cur->_col = RED;if (kv.first > parent->_kv.first){parent->_right = cur;}else if (kv.first < parent->_kv.first){parent->_left = cur;}cur->_parent = parent;//现在才是真正的插入后调节红黑树的平衡的时候while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left)//先分parent是grandfather的左还是右这一大类//这样才可以确定uncle是grandfather的左还是右//之后,由于c的位置在哪都可以,所以不用讨论c的情况//但是若是uncle为空或者为黑色,就需要讨论c的位置了{Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED){//  g//p   u//	cparent->_col = uncle->_col = RED;grandfather->_col = BLACK;cur = grandfather;parent = cur->_parent;//如果此时的cur就是根节点//那么这个程序这个继续往上判断就没有必要了,别忘了根节点是黑色}else if(uncle==nullptr||uncle->_col==BLACK){//    g//p        u//   c      if (cur == parent->_left){RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}//    g//p        u//         celse if (cur == parent->_right){RotateL(parent);RotateR(grandfather);parent->_col = grandfather->_col = RED;cur->_col = BLACK;}}break;}else if (parent == grandfather->_right){Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){//  g//u   p//			cparent->_col = uncle->_col = RED;grandfather->_col = BLACK;cur = grandfather;parent = cur->_parent;//如果此时的cur就是根节点//那么这个程序这个继续往上判断就没有必要了,所以才要判空// 但要是这样的话,根节点此时就是红色的呀,这好办,在最后加一个// 总的:将根节点的颜色置为黑色即可。(虽然很暴力,但是很有用)//别忘了根节点是黑色}else if (uncle == nullptr || uncle->_col == BLACK){//    g//u       p//           cif (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}//    g//u        p//         celse if (cur == parent->_right){RotateR(parent);RotateL(grandfather);parent->_col = grandfather->_col = RED;cur->_col = BLACK;}}}break;}_root->_col = BLACK;return true;
}

大家看这代码,听我来给大家总结一下:

 

以上这两张图,是我认为 本章最核心的部分,就是理清楚各个情况即可。

2.3 红黑树的查找

按二叉搜索树逻辑实现即可,搜索效率为 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.4 红黑树的验证

这⾥获取最长路径和最短路径,检查最长路径不超过最短路径的2倍是不可行的,因为就算满足这个条 件,红黑树也可能颜色不满足规则,当前暂时没出问题,后续继续插入还是会出问题的。所以我们还 是去检查4点规则,满足这4点规则,⼀定能保证最长路径不超过最短路径的2倍。 (因为咱们前面说过,只有保证4点规则,才可以保证接下来的一切)

1.规则1枚举颜色类型,天然实现保证了颜色不是黑色就是红色。

2.规则2直接检查根即可。(如果根是红色,就直接返回false即可)

3.规则3前序遍历检查,遇到红色结点查孩子不太方便,因为孩子有两个,且不⼀定存在,反过来检 查父亲的颜色就方便多了。

4.规则4前序遍历,遍历过程中用形参记录跟到当前结点的blackNum(黑色结点数量),前序遍历遇到 黑色结点就++blackNum,走到空就计算出了⼀条路径的黑色结点数量。再任意⼀条路径黑色结点 数量作为参考值,依次比较即可。

 接下来来看代码:
 

bool Check(Node* root, int blackNum, const int refNum)
{if (root == nullptr){// 前序遍历走到空时,意味着一条路径走完了if (blackNum != refNum){cout << "存在黑色结点的数量不相等的路径" << endl;return false;}return true;}// 检查孩子不太方便,因为孩子有两个,且不一定存在,反过来检查父亲就方便多了if (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 IsBalanceTree()
{if (_root == nullptr)return true;if (_root->_col == RED)return false;// 参考值int refNum = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK){++refNum;}cur = cur->_left;}return Check(_root, 0, refNum);
}

OK,还有一个红黑树的删除,还是一样,在这就不做讲解了,大家有兴趣的,可以下去自行研究。

本篇完............... 

相关文章:

高阶数据结构——红黑树实现

目录 1.红黑树的概念 1.1 红黑树的规则&#xff1a; 1.2 红黑树的效率 2.红黑树的实现 2.1 红黑树的结构 2.2 红黑树的插入 2.2.1 不旋转只变色&#xff08;无论c是p的左还是右&#xff0c;p是g的左还是右&#xff0c;都是一样的变色处理方式&#xff09; 2.2.2 单旋变色…...

java综合交易所13国语言,股票,区块链,外汇,自带客服系统运营级,有测试

这套pc和H5是一体的&#xff0c;支持测试&#xff0c;目前只有外汇和区块链&#xff0c;某站居然有人卖3.8w&#xff0c;还觉得自己这个价格很好 自带客服系统&#xff0c;虽然是老的&#xff0c;但是可玩性还是很高的&#xff0c;也支持c2c&#xff0c;理财&#xff0c;质押&a…...

六:操作系统虚拟内存之缺页中断

深入理解操作系统&#xff1a;缺页中断 (Page Fault) 的处理流程 在上一篇文章中&#xff0c;我们介绍了虚拟内存和按需调页 (Demand Paging) 的概念。虚拟内存为每个进程提供了巨大的、独立的虚拟地址空间&#xff0c;并通过页表 (Page Table) 将虚拟页面 (Virtual Page) 映射…...

iOS 15.4.1 TrollStore(巨魔商店)安装教程详解:第二篇

&#x1f680; iOS 15.4.1 TrollStore&#xff08;巨魔商店&#xff09;安装教程详解 ✨ 前言&#x1f6e0;️ 如何安装 TrollStore&#xff1f;第一步&#xff1a;打开 Safari 浏览器第二步&#xff1a;选择对应系统版本安装方式第三步&#xff1a;访问地址&#xff0c;下载配…...

【JAVA】比较器Comparator与自然排序(28)

JAVA 核心知识点详细解释 Java中比较器Comparator的概念和使用方法 概念 Comparator 是 Java 中的一个函数式接口,位于 java.util 包下。它用于定义对象之间的比较规则,允许我们根据自定义的逻辑对对象进行排序。与对象的自然排序(实现 Comparable 接口)不同,Comparat…...

bitbar环境搭建(ruby 2.4 + rails 5.0.2)

此博客为武汉大学WA学院网络安全课程&#xff0c;理论课大作业Web环境搭建。 博主搭了2天&#xff01;&#xff01;&#xff01;血泪教训是还是不能太相信ppt上的教程。 一开始尝试了ppt上的教程&#xff0c;然后又转而寻找网络资源 cs155源代码和docker配置&#xff0c;做到…...

Spring Boot接口通用返回值设计与实现最佳实践

一、核心返回值模型设计&#xff08;增强版&#xff09; package com.chat.common;import com.chat.util.I18nUtil; import com.chat.util.TraceUtil; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter;import java.io.Serializable;/*** 功能: 通…...

线上 Linux 环境 MySQL 磁盘 IO 高负载深度排查与性能优化实战

目录 一、线上告警 二、问题诊断 1. 系统层面排查 2. 数据库层面分析 三、参数调优 1. sync_binlog 参数优化 2. innodb_flush_log_at_trx_commit 参数调整 四、其他优化建议 1. 日志文件位置调整 2. 生产环境核心参数配置模板 3. 突发 IO 高负载应急响应方案 五、…...

React--函数组件和类组件

React 中的函数组件和类组件是两种定义组件的方式&#xff0c;它们有以下主要区别&#xff1a; 1. 语法与定义方式 函数组件&#xff1a; 是 JavaScript 函数&#xff0c;接收 props 作为参数&#xff0c;返回 JSX。 const MyComponent (props) > {return <div>Hell…...

GitHub 趋势日报 (2025年05月20日)

本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1virattt/ai-hedge-fundAI对冲基金团队⭐ 1781⭐ 31163Python2public-apis/pub…...

uni.getLocation()和uni.openSetting()

文章目录 环境背景问题分析问题1问题2 uni.getLocation()和uni.openSetting()的区别和联系其它uni.getLocation()的failuni.openSetting()的authSetting对象 参考 环境 Windows 11 专业版HBuilder X 4.65微信开发者工具 Stable 1.06.2412050 背景 在小程序开发中&#xff0c…...

医疗行业数据共享新实践:如何用QuickAPI打通诊疗全流程数据壁垒

在医疗行业&#xff0c;数据的高效流转直接影响诊疗效率和患者体验。某三甲医院在数字化转型中发现&#xff0c;虽然已积累大量核心业务数据&#xff0c;但各科室系统间的数据互通仍存在明显瓶颈——检验科的报告无法实时同步至门诊系统&#xff0c;药房库存数据与采购系统脱节…...

管理会议最佳实践:高效协同与价值最大化

1.会前准备:明确目标与计划 1.1 明确会议目的 1.1.1 必要性评估 开会前需自问是否真的需要开会,若问题可通过邮件、文档或异步沟通解决,则应避免开会,以节省时间和资源。 1.1.2 目标定义 清晰定义会议目标,如决策、信息同步、创意讨论等,并提前告知参与者,使大家明确参…...

万物智联,重塑未来:鸿蒙操作系统的实战突破与生态崛起

鸿蒙操作系统&#xff08;HarmonyOS&#xff09;作为华为自主研发的分布式操作系统&#xff0c;自2019年发布以来&#xff0c;已从技术探索迈入大规模商用阶段。截至2025年&#xff0c;鸿蒙系统不仅成为全球第二大移动操作系统&#xff0c;更在政企数字化、工业制造、金融科技等…...

人工智能路径:技术演进下的职业发展导航

当生成式AI能够自主完成创意设计、商业分析和代码编写时&#xff0c;职业发展的传统路径正在被重新测绘。人工智能路径不再是一条预设的直线&#xff0c;而演变为包含多重可能性的动态网络——未来的职业成功&#xff0c;将取决于在技术变革中持续定位自身价值节点的能力。 一…...

深入理解Java虚拟机之垃圾收集器篇(垃圾回收器的深入解析待完成TODO)

目录 **一. 如何判断对象的存亡**引用计数算法:可达性分析算法: **二. Java中的四种引用****三. 垃圾回收算法****1. 标记 - 清除算法****2. 标记 - 复制算法****3. 标记 - 整理算法****4. 分代收集理论**(了解即可) **四. 十种主流垃圾收集器****3.1 Serial 收集器****3.2 Par…...

牛客网 NC16407 题解:托米航空公司的座位安排问题

牛客网 NC16407 题解&#xff1a;托米航空公司的座位安排问题 题目分析 解题思路 本题可以采用深度优先搜索(DFS)来解决&#xff1a; 从左上角开始&#xff0c;按行优先顺序遍历每个座位对于每个座位&#xff0c;有两种选择&#xff1a; 选择该座位&#xff08;如果满足条件…...

拉普拉斯高斯(LoG)滤波器掩模的注意事项

目录 问题&#xff1a; 解答&#xff1a; 一、高斯函数归一化&#xff1a;消除幅度偏差 1. 归一化的定义 2. 为何必须归一化&#xff1f; 二、拉普拉斯系数和为零&#xff1a;抑制直流项干扰 1. 拉普拉斯算子的特性 2. 系数和不为零的后果 三、直流项如何影响零交叉点&…...

OSPF基础实验-多区域

互联接口、IP地址如下图所示&#xff0c;所有设备均创建Loopback0&#xff0c;其IP地址为10.0.x.x/24&#xff0c;其中x为设备编号。 R1、R3的所有接口以及R2的GE0/0/4接口属于OSPF区域2&#xff0c;R2、R4的Loopback0接口及互联接口属于OSPF区域0&#xff0c;R4、R5的互联接口…...

ERP 与 WMS 对接深度解析:双视角下的业务与技术协同

在企业数字化运营的复杂体系中&#xff0c;ERP&#xff08;企业资源规划&#xff09;与 WMS&#xff08;仓储管理系统&#xff09;的有效对接&#xff0c;已成为优化供应链管理、提升运营效率的关键环节。本文将从 ERP 和 WMS 两个核心视角出发&#xff0c;深度剖析两者对接过程…...

基于 Node.js 的 HTML 转 PDF 服务

这是一个基于 Node.js 开发的 Web 服务&#xff0c;主要功能是将 HTML 内容转换为 PDF 文件。项目使用了 Express 作为 Web 框架&#xff0c;Puppeteer 作为 PDF 生成引擎&#xff0c;提供了简单易用的 API 接口。前端开发人员提供了一个简单而强大的 HTML 转 PDF 解决方案&…...

Java阻塞队列(BlockingQueue)的使用:ArrayBlockingQueue类、LinkedBlockingQueue类

1、阻塞队列的介绍 Java 中的阻塞队列(BlockingQueue)‌ 是多线程编程中用于协调生产者和消费者线程的重要工具,属于 java.util.concurrent 包。它的核心特点是:‌当队列为空时,消费者线程会被阻塞,直到队列中有新元素;当队列满时,生产者线程会被阻塞,直到队列有空闲…...

esp32cmini SK6812 2个方式

1 #include <SPI.h> // ESP32-C系列的SPI引脚 #define MOSI_PIN 7 // ESP32-C3/C6的SPI MOSI引脚 #define NUM_LEDS 30 // LED灯带实际LED数量 - 确保与实际数量匹配&#xff01; #define SPI_CLOCK 10000000 // SPI时钟频率 // 颜色结构体 st…...

2025年 PMP 6月 8月 专题知识

2025年 PMP 6月 8月 专题知识 文章目录 2025年 PMP 6月 8月 专题知识三点估算1. 概念:2. 原理: 决策树1. 概念:2. 步骤: 真题 三点估算 1. 概念: 三点估算常用于估算活动持续时间&#xff08;也可以用于估算成本&#xff09;&#xff1b;源自计划评审技术&#xff08;PERT&am…...

一文理解TCP与UDP

Socket套接字 Socket套接字&#xff0c;是由系统提供用于网络通信的技术&#xff0c;是基于TCP/IP协议的网络通信的基本操作单元。 基于Socket套接字的网络程序开发就是网络编程。 Socket套接字主要针对传输层协议划分为如下三类&#xff1a; 流套接字&#xff1a;使用传输层…...

智能指针RAII

引入&#xff1a;智能指针的意义是什么&#xff1f; RAll是一种利用对象生命周期来控制程序资源&#xff08;如内存、文件句柄、网络连接、互斥量等等&#xff09;的简单技术。 在对象构造时获取资源&#xff0c;接着控制对资源的访问使之在对象的生命周期内始终保持有效&#…...

AI护航化工:《山西省危化品视频智能分析指南》下的视频分析重构安全体系

化工和危化品行业的AI智能视频分析应用&#xff1a;构建安全与效率新范式 一、行业背景与挑战 化工和危化品行业是国民经济的重要支柱&#xff0c;但生产过程涉及高温、高压、易燃易爆等高风险场景。传统安全监管依赖人工巡检和固定监控设备&#xff0c;存在效率低、盲区多、…...

GitHub SSH Key 配置详细教程(适合初学者,Windows版)-学习记录4

GitHub SSH Key 配置详细教程&#xff08;适合初学者&#xff0c;Windows版&#xff09; 本教程适用于在 Windows 系统下&#xff0c;将本地 Git 仓库通过 SSH 方式推送到 GitHub&#xff0c;适合没有配置过 SSH key 的初学者。 1. 检查是否已有 SSH key 打开 Git Bash 或 Po…...

初识Linux · NAT 内网穿透 内网打洞 代理

目录 前言&#xff1a; 内网穿透和打洞 NAPT表 内网穿透 内网打洞 正向/反向代理 前言&#xff1a; 本文算是网络原理的最后一点补充&#xff0c;为什么说是补充呢&#xff0c;因为我们在前面第一次介绍NAT的时候详细介绍的是报文从子网到公网&#xff0c;却没有介绍报文…...

docker-compose使用详解

Docker-Compose 是 Docker 官方提供的容器编排工具&#xff0c;用于简化多容器应用的定义、部署和管理。其核心功能是通过 YAML 配置文件&#xff08;docker-compose.yml&#xff09;定义服务、网络和存储卷&#xff0c;并通过单一命令实现全生命周期的管理。以下从核心原理、安…...

使用计算机视觉实现目标分类和计数!!超详细入门教程

什么是物体计数和分类 在当今自动化和技术进步的时代&#xff0c;计算机视觉作为一项关键工具脱颖而出&#xff0c;在物体计数和分类任务中提供了卓越的功能。 无论是在制造、仓储、零售&#xff0c;还是在交通监控等日常应用中&#xff0c;计算机视觉系统都彻底改变了我们感知…...

并发编程中的对象组合的哲学

文章目录 引言对象组合与安全委托实例封闭技术基于监视器模式的对象访问对象不可变性简化委托原子维度的访问现有容器的并发安全的封装哲学使用继承使用组合小结参考引言 本文将介绍通过封装技术,保证开发者不对整个程序进行分析的情况下,就可以明确一个类是否是线程安全的,…...

03-Web后端基础(Maven基础)

1. 初始Maven 1.1 介绍 Maven 是一款用于管理和构建Java项目的工具&#xff0c;是Apache旗下的一个开源项目 。 Apache 软件基金会&#xff0c;成立于1999年7月&#xff0c;是目前世界上最大的最受欢迎的开源软件基金会&#xff0c;也是一个专门为支持开源项目而生的非盈利性…...

禁忌搜索算法:从原理到实战的全解析

禁忌搜索算法&#xff1a;从原理到实战的全解析 一、算法起源与核心思想 禁忌搜索&#xff08;Tabu Search, TS&#xff09;由美国工程院院士Fred Glover于1986年正式提出&#xff0c;其灵感源于人类的记忆机制——通过记录近期的搜索历史&#xff08;禁忌表&#xff09;&…...

从加密到信任|密码重塑车路云一体化安全生态

目录 一、密码技术的核心支撑 二、典型应用案例 三、未来发展方向 总结 车路云系统涉及海量实时数据交互&#xff0c;包括车辆位置、传感器信息、用户身份等敏感数据。其安全风险呈现三大特征&#xff1a; 开放环境威胁&#xff1a;V2X&#xff08;车与万物互联&#xff0…...

【ffmpeg】SPS与PPS的概念

PPS&#xff08;Picture Parameter Set&#xff09;详解 PPS&#xff08;图像参数集&#xff09;是H.264/H.265视频编码标准中的关键数据结构&#xff0c;与SPS&#xff08;序列参数集&#xff09;共同组成视频的解码配置信息&#xff0c;直接影响视频的正确解码和播放。以下是…...

Java垃圾回收与JIT编译优化

1. Java中的垃圾回收 垃圾回收是Java内存管理的核心,负责自动回收不再被应用程序引用的对象内存,从而防止内存泄漏并优化资源使用。以下详细介绍垃圾回收的机制、算法及优化实践。 1.1 垃圾回收的必要性 垃圾回收解决了手动内存管理中的常见问题,如内存泄漏和悬空指针。它…...

mmaction2——tools文件夹下

build_rawframes.py 用法示例 python tools/data/build_rawframes.py data/videos data/frames --task rgb --level 2 --ext mp4 --use-opencv --num-worker 8总结&#xff1a; 只需要 RGB 帧&#xff0c;推荐 --use-opencv&#xff0c;简单高效&#xff0c;无需额外依赖。 …...

论文阅读:Next-Generation Database Interfaces:A Survey of LLM-based Text-to-SQL

地址&#xff1a;Next-Generation Database Interfaces: A Survey of LLM-based Text-to-SQL 摘要 由于用户问题理解、数据库模式解析和 SQL 生成的复杂性&#xff0c;从用户自然语言问题生成准确 SQL&#xff08;Text-to-SQL&#xff09;仍是一项长期挑战。传统的 Text-to-SQ…...

Devicenet主转Profinet网关助力改造焊接机器人系统智能升级

某汽车零部件焊接车间原有6台焊接机器人&#xff08;采用Devicenet协议&#xff09;需与新增的西门子S7-1200 PLC&#xff08;Profinet协议&#xff09;组网。若更换所有机器人控制器或上位机系统&#xff0c;成本过高且停产周期长。 《解决方案》 工程师选择稳联技术转换网关…...

【HTML-5】HTML 实体:完整指南与最佳实践

1. 什么是 HTML 实体&#xff1f; HTML 实体是一种在 HTML 文档中表示特殊字符的方法&#xff0c;这些字符如果直接使用可能会与 HTML 标记混淆&#xff0c;或者无法通过键盘直接输入。实体由 & 符号开始&#xff0c;以 ; 分号结束。 <p>这是一个小于符号的实体&am…...

MySQL 索引详解与原理分析

MySQL 索引详解与原理分析 一、什么是索引&#xff1f; 索引&#xff08;Index&#xff09;是数据库表中一列或多列的值进行排序的一种数据结构&#xff0c;可以加快数据的检索速度。索引类似于书本的目录&#xff0c;通过目录可以快速定位到想要的内容&#xff0c;而不用全书…...

游戏引擎学习第303天:尝试分开对Y轴和Z轴进行排序

成为我们自己的代码精灵α 所以现在应该可以正常使用了。不过&#xff0c;这两周我们没办法继续处理代码里的问题&#xff0c;而之前留在代码里的那个问题依然存在&#xff0c;没有人神奇地帮我们修复&#xff0c;这让人挺无奈的。其实我们都希望有个神奇的“代码仙子”&#…...

javaweb-html

1.交互流程&#xff1a; 浏览器向服务器发送http请求&#xff0c;服务器对浏览器进行回应&#xff0c;并发送字符串&#xff0c;浏览器能对这些字符串&#xff08;html代码&#xff09;进行解释&#xff1b; 三大web语言&#xff1a;&#xff08;1&#xff09;html&#xff1a…...

3.2.3

# 导入必要的库 import onnx import numpy as np from PIL import Image import onnxruntime as ort # 定义预处理函数&#xff0c;用于将图片转换为模型所需的输入格式 def preprocess(image_path): input_shape (1, 1, 64, 64) # 模型输入期望的形状&#xff0c;这里…...

Redis 8.0 GA,重回开源

在数字化浪潮的推动下&#xff0c;实时数据处理已成为现代应用的核心需求。作为全球广泛使用的 NoSQL 数据库&#xff0c;Redis 8.0 不仅通过 30 余项性能改进重新定义了实时数据处理的速度极限&#xff0c;更通过整合社区资源与开放授权模式&#xff0c;进一步巩固其在开源生态…...

心联网(社群经济)视角下开源AI智能名片、链动2+1模式与S2B2C商城小程序源码的协同创新研究

摘要&#xff1a;在心联网&#xff08;社群经济&#xff09;理论框架下&#xff0c;本文构建了开源AI智能名片、链动21模式与S2B2C商城小程序源码的技术协同体系&#xff0c;提出"情感连接-利益驱动-生态裂变"三维创新模型。通过实证分析与案例研究&#xff0c;验证该…...

【图像大模型】Hunyuan-DiT:腾讯多模态扩散Transformer的架构创新与工程实践

Hunyuan-DiT&#xff1a;腾讯多模态扩散Transformer的架构创新与工程实践 一、架构设计与技术创新1.1 核心架构解析1.2 关键技术突破1.2.1 多粒度训练策略1.2.2 动态路由MoE 二、系统架构解析2.1 完整生成流程2.2 性能对比 三、实战部署指南3.1 环境配置3.2 基础推理代码3.3 高…...

TASK04【Datawhale 组队学习】构建RAG应用

目录 将LLM接入LangChain构建检索问答链运行成功图遇到的问题 langchain可以便捷地调用大模型&#xff0c;并将其结合在以langchain为基础框架搭建的个人应用中。 将LLM接入LangChain from langchain_openai import ChatOpenAI实例化一个 ChatOpenAI 类,实例化时传入超参数来…...

YOLOv11旋转目标检测Hrsc2016

from ultralytics import YOLOmodel YOLO(/kaggle/input/model-v11-obb/yolo11n-obb.pt) model.train(data/kaggle/input/hrscobb4/HRSC-YOLO/data.yaml, epochs30) 1使用的训练平台为Kaggle 数据集&#xff1a;HRSC的三种形式 一级分类&#xff1a;船 有水平框版本&…...