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

数据结构:红黑树

为什么要以这个结构为题?那就要追溯到C++STL库中的两种map/set,分别基于红黑树与哈希表,我是根本分不清楚。为了搞清楚其区别,我会重点聊聊红黑树和哈希表。

当然也会简单介绍一下树的结构。


树 Tree

首先需要简单了解树这个数据结构的一些术语。

度:树中某个节点的孩子的个数称为节点的度,整个树中节点的度的最大值即为树的度。

叶子节点:度为零的节点,又叫终端节点。

分支节点:度大于零的节点,有非终端节点。

结点的深度:是从根结点开始自顶向下逐层累加的。

结点的高度:是从叶结点开始自底向上逐层累加的。

树的高度(或深度):是树中结点的最大层数。

路径和路径长度。树中两个结点之间的路径是由这两个结点之间所经过的结点序列构成的,而路径长度是路径上所经过的边的个数。

有序树和无序树:树中结点的各子树从左到右是有次序的,不能互换,称该树为有序树,否则称为无序树。

森林:多个互不相交的树的集合。

树的表示方法有三种。

双亲表示法:一个节点保存自己的数据和父节点的指针。

struct TreeNode {int data;TreeNode* parent;TreeNode(int data) :data(data), parent(NULL) {}
};

孩子表示法:一个节点保存自己数据之外,保存其子节点的指针集合,可以是数组或链表。

struct ChildNode {TreeNode* child;ChildNode* next;ChildNode(TreeNode* node) : child(node), next(nullptr) {}
};
//这里用链表,也可以用vector
struct TreeNode {int data;ChildNode* firstChild;TreeNode(int data) : data(data), firstChild(nullptr) {}
};

双亲兄弟表示法:因为对于任何一个节点,第一个孩子和下一个兄弟如果存在就是唯一的,能够将任意一棵树变为二叉树。

struct TreeNode {int data;TreeNode* firstChild;//第一个孩子TreeNode* nextSibling;//下一个兄弟TreeNode(int val) : data(val), firstChild(nullptr), nextSibling(nullptr) {}
};

斜树:所有的结点都只有左子树的二叉树叫左斜树,右边一样。

满二叉树:每层的节点都填满了。

完全二叉树:就是满二叉树从后往前按顺序删掉几个节点。(现在知道了,堆因为底层是数组,所以按顺序排成树一定是完全二叉树)

二叉排序树:左子树上所有节点的值均小于根节点的值,右子树上所有节点的值均大于根节点的值,任意子树都满足上述性质。

平衡二叉树:树上任一结点的左子树和右子树的深度之差不超过1,即AVL树。

二叉树的三种遍历方法,感觉是根据遍历根节点的位置定义的。

前序遍历:根节点->左子树->右子树。

void preOrder(TreeNode* root) {if (!root) return;cout << root->val << " ";preOrder(root->left);preOrder(root->right);
}

中序遍历:左子树->根节点->右子树。

void inOrder(TreeNode* root) {if (!root) return;inOrder(root->left);cout << root->val << " ";inOrder(root->right);
}

​​​​​​​前序遍历:左子树->右子树->根节点。

void postOrder(TreeNode* root) {if (!root) return;postOrder(root->left);postOrder(root->right);cout << root->val << " ";
}

​​​​​​​平衡二叉树

平衡二叉树(AVL Tree)最大的作用就是查找,AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。

我们将二叉树上结点的左子树深度减去右子树深度的值称为平衡因子BF (Balance Factor) , 那么所有结点的平衡因子只可能是-1、0和1。只要二叉树上有一个结点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。所以在新结点插入后,若造成查找路径上的某个结点不再平衡,则受平衡因子的约束做出相应的调整。

同时,平衡二叉树必须遵循二叉搜索树(BST)的基本性质:左子节点的值 < 根节点的值 < 右子节点的值。这是所有平衡二叉树保持高效查找能力的前提条件。

如何调整?有以下四种情况,调整的对象都是最小不平衡子树。

LL平衡旋转(右单旋转):

RR平衡旋转(左单旋转):

LR平衡旋转(先左后右双旋转):

RL平衡旋转(先右后左双旋转):

可以看到,这种动态调整的方法使平衡二叉树十分平衡。

红黑树

相较于平衡二叉树,红黑树不受平衡因子制约,用颜色替代严格平衡,降低维护成本,只需要满足以下5条规则。

1、根节点为黑色

2、每个节点不是黑色就是红色

3、所有叶子节点(空节点,NIL节点)都是黑色的

4、不能有两个连续的红色节点(可以连续黑哦)

5、从任一节点到其每个叶子节点(空节点)的所有路径都包含相同数目的黑色节点(称为该节点的黑高)。

struct RBTreeNode {int data;Color color;RBTreeNode* left;RBTreeNode* right;RBTreeNode* parent;RBTreeNode(int val, Color c) : data(val), color(c), left(nullptr), right(nullptr), parent(nullptr) {}
};

​​​​​​​在插入新节点时,需要保持二叉搜索树性质和保持红黑性质。新节点一律被标为红色。

如果父节点是黑色,不用动。如果父节点是红色,看父节点的兄弟节点是什么颜色,他要是黑色或者NIL节点,旋转调整。兄弟节点颜色呼唤。要是他也是红色,把他俩的红色改成黑色,向上递归。

以下为C++实现。

//枚举标记颜色
enum  Color { RED, BLACK };
struct RBTreeNode {int data;Color color;RBTreeNode* left;//左子RBTreeNode* right;//右子RBTreeNode* parent;//父RBTreeNode(int val, Color c = RED) : data(val), color(c), left(nullptr), right(nullptr), parent(nullptr) {}RBTreeNode(int val, Color c = RED, RBTreeNode* parent, RBTreeNode* left, RBTreeNode* right) : data(val), color(c), left(left), right(right), parent(parent) {}RBTreeNode(Color c = RED) : data(0), color(c), left(nullptr), right(nullptr), parent(nullptr) {}
};
//树主体,封装各种操作
class RBTree {
public:RBTree() {NIL = new RBTreeNode(BLACK);root = NIL;}RBTreeNode* root;//根节点RBTreeNode* NIL;//代表NIL节点//插入删除查找void insert(int val);void remove(int val);RBTreeNode* search(int val);
private://内部调整方法void leftRotate(RBTreeNode* x);void rightRotate(RBTreeNode* y);void insertFixup(RBTreeNode* z);void deleteFixup(RBTreeNode* x);
};
RBTreeNode* RBTree::search(int val) {RBTreeNode* current = root;while (current != NIL && val != current->data) {if (val < current->data) {current = current->left;}else {current = current->right;}}return current;
}
//左旋(传旧的根节点)
void RBTree::leftRotate(RBTreeNode* x) {RBTreeNode* y = x->right;x->right = y->left;if (y->left != NIL) {y->left->parent = x;}y->parent = x->parent;if (x->parent == NIL) {root = y;}else if (x == x->parent->left) {x->parent->left = y;}else {x->parent->right = y;}y->left = x;x->parent = y;
}
//右旋
void RBTree::rightRotate(RBTreeNode* y) {RBTreeNode* x = y->left;y->left = x->right;if (x->right != NIL) {x->right->parent = y;}x->parent = y->parent;if (y->parent == NIL) {root = x;}else if (y == y->parent->right) {y->parent->right = x;}else {y->parent->left = x;}x->right = y;y->parent = x;
}
void RBTree::insert(int val) {//新节点必须是红节点RBTreeNode* z = new RBTreeNode(val, RED, NIL, NIL, NIL);RBTreeNode* y = NIL;RBTreeNode* x = root;//标准BST插入(二叉搜索树)//y一直是x的父节点//从根开始探测while (x != NIL) {y = x;if (z->data < x->data) {x = x->left;}else {x = x->right;}}//确定z的父节点z->parent = y;//确定y的子节点if (y == NIL) {root = z;}else if (z->data < y->data) {y->left = z;}else {y->right = z;}//进行修复insertFixup(z);
}
void RBTree::insertFixup(RBTreeNode* z) {//只有红红冲突才需要修复while (z->parent->color == RED) {if (z->parent == z->parent->parent->left) {//看所谓的叔叔节点是什么颜色RBTreeNode* y = z->parent->parent->right;if (y->color == RED) {z->parent->color = BLACK;y->color = BLACK;//将叔叔和父亲的父节点染红z->parent->parent->color = RED;//现在这个父节点成为新的可能产生冲突的红节点z = z->parent->parent;}else {//检查一下是否需要左旋if (z == z->parent->right) {//防止影响后续变色操作z = z->parent;leftRotate(z);}z->parent->color = BLACK;z->parent->parent->color = RED;rightRotate(z->parent->parent);}}else {RBTreeNode* y = z->parent->parent->left;if (y->color == RED) {z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;z = z->parent->parent;}else {//检查一下是否需要右旋if (z == z->parent->left) {z = z->parent;rightRotate(z);}z->parent->color = BLACK;z->parent->parent->color = RED;leftRotate(z->parent->parent);}}}root->color = BLACK;
}

​​​​​​​我还没有写红黑树的删除操作,因为其是最难理解的操作了。在此之前,需要先回顾一下一般二叉搜索树的删除方法。

对于一般二叉搜索树,“删除有两个子节点的节点”最终会转换为“删除拥有一个子节点的节点”或者“删除没有子节点的节点”,要么直接删掉要么让子树代替。那么对于红黑树的删除也是一样的,但是删除不同于插入,他可能删掉的是黑色节点从而破坏红黑树的黑高一致性。那么此时的删除就需要分情况讨论了。

现在详细谈谈删除没有子节点的节点时,且其还是黑色的情况。为了在后续向上或者向下递归时方便理解,我引入了“问题根”的概念(我瞎起的只是为了方便理解),问题根是某一串子树的根节点,有这样的特性:如果目标节点的兄弟节点为黑色,那么问题根两个子树黑高相差1,大的那边的子节点的两颗子树与另一边的整个子树的黑高相同。

然后我们看图理解。

在知道原理之后,我们再来写C++实现。

//找到右子树中的最小值,即后继节点
RBTreeNode* RBTree::minimum(RBTreeNode* node) {while (node->left != NIL) {node = node->left;}return node;
}
//节点的代替方法,后者代替前者
void RBTree::transplant(RBTreeNode* u, RBTreeNode* v) {if (u->parent == NIL) {root = v;}else if (u == u->parent->left) {u->parent->left = v;}else {u->parent->right = v;}v->parent = u->parent;
}
//删除操作
void RBTree::remove(int val) {RBTreeNode* z = search(val);if (z == NIL) { return; }RBTreeNode* y = z;//记录目标节点的颜色Color y_original_color = y->color;//分情况if (z->left == NIL && z->right != NIL) {//只有右子树,直接换transplant(z, z->right);}else if (z->right == NIL && z->left != NIL) {//只有左子树,直接换transplant(z, z->left);}else if (z->left == NIL && z->right == NIL) {if (z->color == RED) {//是红色,直接换成NILtransplant(z, z->right);}else {//是黑色进行调整//替换掉以后,再调整transplant(z, z->right);//z是问题根下黑高少1的子树的根节点deleteFixup(z);}}else if (z->left != NIL && z->left != NIL) {//处理左右都有子树的情况//找到后继节点y = minimum(z->right);//更新目标节点的颜色y_original_color = y->color;//替换数据z->data = y->data;//要删的节点变化z = y;if (z->left == NIL && z->right->color == RED) {//只有右子树,直接换transplant(z, z->right);}else if (z->right == NIL && z->left->color == RED) {//只有左子树,直接换transplant(z, z->left);}else if (z->left == NIL && z->right == NIL) {if (z->color == RED) {//是红色,直接换成NILtransplant(z, z->right);}else {//是黑色进行调整//替换掉以后,再调整transplant(z, z->right);//z是问题根下黑高少1的子树的根节点deleteFixup(z);}}}//释放内存delete z;
}
//调整
void RBTree::deleteFixup(RBTreeNode* x) {//这里的x就是目标节点,x递归到根节点时跳出循环//x永远是问题根的出问题的子树的根节点while (x != root) {if (x == x->parent->left) {//记录兄弟节点RBTreeNode* w = x->parent->right;if (w->color == RED) {w->color = BLACK;x->parent->color = RED;leftRotate(x->parent);//问题根下移,更新兄弟节点w = x->parent->right;}//此时兄弟节点绝对为黑色,不用进入循环if (w->left->color == BLACK && w->right->color == BLACK) {w->color = RED;//问题根上移,进入循环调整,目标节点更新x = x->parent;}else {//看看是否需要右旋if (w->right->color == BLACK) {w->left->color = BLACK;//防止影响下一步染色w->color = RED;rightRotate(w);w = x->parent->right;}w->color = x->parent->color;x->parent->color = BLACK;w->right->color = BLACK;leftRotate(x->parent);//跳出循环x = root;}}else { RBTreeNode* w = x->parent->left;if (w->color == RED) {w->color = BLACK;x->parent->color = RED;rightRotate(x->parent);w = x->parent->left;}if (w->left->color == BLACK && w->right->color == BLACK) {w->color = RED;x = x->parent;}else {//看看是否需要左旋if (w->left->color == BLACK) {w->right->color = BLACK;//防止影响下一步染色w->color = RED;leftRotate(w);w = x->parent->left;}w->color = x->parent->color;x->parent->color = BLACK;w->left->color = BLACK;rightRotate(x->parent);x = root;}}}//保持根节点为黑色x->color = BLACK;
}

​​​​​​​总的来说,红黑树最坏情况下查找/插入/删除均为O(log n),避免BST退化成链表的O(n)风险,旋转操作集中在局部子树,在插入删除方面相比于平衡二叉树性能好了许多。


小结

红黑树的逻辑还真是复杂,下次我会讨论哈希表,以及C++的STL库中两种set/map的使用,敬请期待。

如有补充纠正欢迎留言。

相关文章:

数据结构:红黑树

为什么要以这个结构为题&#xff1f;那就要追溯到CSTL库中的两种map/set&#xff0c;分别基于红黑树与哈希表&#xff0c;我是根本分不清楚。为了搞清楚其区别&#xff0c;我会重点聊聊红黑树和哈希表。 当然也会简单介绍一下树的结构。 树 Tree 首先需要简单了解树这个数据结…...

nginx配置ssl证书,实现https安全访问.

前置条件: 名称 ip地址端口号nginx服务器192.168.59.3080/443server服务器190.168.59.318080/8081/8082 安装nginx服务: 参见: 编译安装nginx-CSDN博客 启动后端web服务器192.168.59.31: (#后端要被代理的web服务器要有docker服务并且配置相关的加速服务) 拉取tomcat容器…...

《当区块链穿上防弹衣:落盘加密技术全景拆解》

落盘加密是区块链技术中一项重要的数据安全机制,主要用于保护节点本地存储的敏感数据不被非法访问。本文将全面解析区块链落盘加密的技术原理、实施方法、应用价值,并与其他加密技术进行比较分析。 🔒 落盘加密的技术原理 落盘加密(Disk Encryption)是指对存储在物理磁盘…...

新HTML5

在新HTML5中&#xff0c;DOCTYPE声明以及字符编码声明都非常简单&#xff1a; <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>Document</title> </head> <body>内容 </body> </html>HTM…...

DeepSeek-MLA

MLA 结构 需要缓存 KV 向量共用的压缩隐特征K 向量多头共享的带位置编码的向量 为什么带有位置信息的 Q 向量来自于隐特征向量&#xff0c;而带有位置的 K 向量来自于 H 向量且共享呢&#xff1f; 最好的方法肯定是从H向量直接计算并且不共享&#xff0c;但是会大大增加显存使…...

SQL:数据类型(Data Types)

目录 数字数据类型&#xff08;Numeric data types) 非数据类型&#xff08;Non-numeric data types) 日期和时间类型&#xff08;Date and Time Types) NULL&#xff08;缺失或未知值&#xff09; 当你在数据库中创建表格时&#xff0c;你必须指明表中每一列可以保存的数据…...

AF3 OpenFoldBatchCollator类解读

AlphaFold3 data_modules 模块的 OpenFoldBatchCollator 类将一个蛋白质样本列表中的多个字典按键合并,并对每个键值进行 torch.stack 操作,打包成一个批次(batch)。通过定义 OpenFoldBatchCollator类的 __call__ 方法,可以将类的实例当作函数来调用,相当于自定义的批次打…...

手搓多模态-06 数据预处理

前情回顾 我们目前实现了视觉模型的编码器部分&#xff0c;然而&#xff0c;我们所做的是把一张图片编码嵌入成了许多个上下文相关的嵌入向量&#xff0c;然而我们期望的是一张图片用一个向量来表示&#xff0c;从而与文字的向量做点积形成相似度&#xff08;参考手搓多模态-01…...

[蓝桥杯] 求和

题目链接 P8772 [蓝桥杯 2022 省 A] 求和 - 洛谷 题目理解 这道题就是公式题&#xff0c;我们模拟出公式后&#xff0c;输出最终结果即可。 本题不难&#xff0c;相信很多同学第一次见到这道题都是直接暴力解题。 两个for循环&#xff0c;测试样例&#xff0c;直接拿下。 #in…...

INFINI Labs 产品更新 | Coco AI 0.3 发布 – 新增支持 Widget 外部站点集成

INFINI Labs 产品更新发布&#xff01;此次更新涵盖 Coco AI 、Easysearch 等产品多项重要升级&#xff0c;重点提升 AI 搜索能力、易用性及企业级优化。 Coco AI v0.3 作为 开源、跨平台的 AI 搜索工具&#xff0c;新增快捷键设置&#xff0c;支持多个聊天会话等功能。Coco A…...

vue3+element-plus多个多选下拉框并搜索

一、下拉框组件&#xff1a; <template> <div class"top-select"> <div class"first-select"> <div v-for"(group, index) in selectGroups" :key"index" class"item-select" > <div class&quo…...

吴恩达深度学习复盘(9)多类分类与SoftMax回归

多类分类 概念 对于分类问题&#xff0c;并非只有0或1两个标签&#xff0c;而是可以有两个以上的开放标签。以手写数字分类问题为例&#xff0c;之前只是区分0和1&#xff0c; 但在实际生活中&#xff0c;如读取信封上的数字或邮政编码&#xff0c;会涉及十个可能的数字识别&…...

【力扣hot100题】(068)有效的括号

犹记得第一次做这题的时候是怎样一番惨状&#xff0c;现在已经得心应手了。 class Solution { public:bool isValid(string s) {stack<char> zhan;for(int i0;i<s.size();i){if(s[i]{||s[i](||s[i][) zhan.push(s[i]);else{if(zhan.empty()) return 0;if(zhan.top(){…...

深度学习篇---Prophet时间序列预测工具

文章目录 前言一、什么是Prophet&#xff1f;易用性自动化灵活性鲁棒性快速拟合 二、Prophet的核心原理1. 趋势模型a. 分段线性模型&#xff08;默认&#xff09;b. 逻辑增长模型 2. 季节性模型3. 节假日效应 三、Prophet使用方法安装ProphetPython基本使用示例1. 准备数据2. 创…...

TDengine JAVA 语言连接器

简介 本节简介 TDengine 最重要且使用最多的连接器, 本节内容是以教科书式方式列出对外提供的接口及功能及使用过程中要注意的技术细节&#xff0c;大家可以收藏起来做为今后开发 TDengine 的参考资料。 taos-jdbcdriver 是 TDengine 的官方 Java 语言连接器&#xff0c;Java…...

vue3工程中使用vditor完成markdown渲染并防止xss攻击

vue3工程中使用vditor完成markdown渲染并防止xss攻击 背景环境解决方案引入依赖 组件封装实现效果 背景 做oj系统时&#xff0c;题目使用的时markdown语法字符串,前端查看时需要将markdown转html再渲染到页面上。 环境 vitevue3pnpm 解决方案 引入依赖 pnpm install vdit…...

Java面向对象编程详解

面向对象编程是Java的核心特性之一&#xff0c;它通过类和对象的概念来解决实际问题&#xff0c;使程序设计更加符合人类对事物的认知方式。本文将深入探讨Java中的面向对象编程概念和特性。 1. 面向对象的基本概念 1.1 什么是面向对象&#xff1f; 面向对象程序设计(Object …...

重温java 系列一 Java基础

文件拷贝的5种方式 传统字节拷贝 public static void main(String[] args) throws IOExecption{try(InputStream is new FileInputStream("source.txt");OutputStream os new FileOutputStream("target.txt")){byte[] buffer new byte[1024];int leng…...

Java基础 4.7

1.成员方法传参机制 引用数据类型的传参机制 引用类型传递的是地址&#xff08;其实也是值&#xff0c;只不过值是地址&#xff09;&#xff0c;可以通过形参影响实参&#xff01; public class MethodParameter01 {public static void main(String[] args) {int[] arr {1,…...

基础IO(一)之回顾C语言文件接口

文章目录 共识原理回顾C文件接口打开文件的方式以w的方式打开文件以a的方式打开文件 stdin & stdout & stderr 共识原理 1.文件内容属性 就算内容是空的&#xff0c;也会有属性&#xff0c;内容和属性(两者都是数据)都要在磁盘当中保存 2.文件分为 打开的文件 和 没…...

PandaAI:一个基于AI的对话式数据分析工具

PandaAI 是一个基于 Python 开发的自然语言处理和数据分析工具&#xff0c;支持问答式&#xff08;ChatGPT&#xff09;的数据分析和报告生成功能。PandaAI 提供了一个开源的框架&#xff0c;主要核心组件包含用于数据处理的数据准备层&#xff08;Pandas&#xff09;以及实现 …...

Rollup详解

Rollup 是一个 JavaScript 模块打包工具&#xff0c;专注于 ES 模块的打包&#xff0c;常用于打包 JavaScript 库。下面从它的工作原理、特点、使用场景、配置和与其他打包工具对比等方面进行详细讲解。 一、 工作原理 Rollup 的核心工作是分析代码中的 import 和 export 语句…...

【NLP 56、实践 ⑬ LoRA完成NER任务】

目录 一、数据文件 二、模型配置文件 config.py 三、数据加载文件 loader.py 1.导入文件和类的定义 2.初始化 3.数据加载方法 代码运行流程 4.文本编码 / 解码方法    ① encode_sentence()&#xff1a; ② decode()&#xff1a; 代码运行流程 ③ padding()&#xff1a; 代码…...

Unity ViewportConstraint

一、组件功能概述 ViewportConstraint是一个基于世界坐标的UI边界约束组件&#xff0c;主要功能包括&#xff1a; 将UI元素限制在父容器范围内支持自定义内边距&#xff08;padding&#xff09;可独立控制水平和垂直方向的约束 二、实现原理 1. 边界计算&#xff08;世界坐…...

项目实战--路由权限

封装 单独抽象成组件&#xff0c;写一个新的关于路由的NewsRouter.jsx&#xff1a; import SideMenu from "../../components/sandbox/SideMenu"; import TopHeader from "../../components/sandbox/TopHeader"; import { Routes, Route } from "re…...

Async 注解原理分析

Async 注解由 Spring 框架提供&#xff0c;被该注解标注的类或方法会在 异步线程 中执行。这意味着当方法被调用时&#xff0c;调用者将不会等待该方法执行完成&#xff0c;而是可以继续执行后续的代码。 Async 注解的使用非常简单&#xff0c;需要两个步骤&#xff1a; 在启…...

pyTorch-迁移学习-图片数据增强-四种天气图片的多分类问题

目录 1.导包 2.加载数据、拼接训练与测试数据的文件夹路径 3数据预处理 3.1数据增强 3.2用分类存储的图片数据创建dataloader 4.加载预训练好的模型 (迁移学习) 4.1固定、修改预训练好的模型 5.将模型拷到GPU上 6.定义优化器与损失函数 7.学习率衰减 8.定义训…...

Linux脚本基础详解

一、基础知识 Linux 脚本主要是指在 Linux 系统中编写的用于自动化执行任务的脚本程序&#xff0c;其中最常用的便是 Bash 脚本。下面我们将从语法、使用方法和示例三个方面详细讲解 Linux 脚本。 1. 脚本简介 定义&#xff1a;Linux 脚本是一系列命令的集合&#xff0c;可以…...

MQTT-Dashboard-数据集成-WebHook、日志管理

常用的 Docker Volume 命令及其用法。 1、创建数据卷 使用 docker volume create 命令可以创建一个新的数据卷。例如&#xff0c;创建一个名为 my_volume 的数据卷&#xff1a; docker volume create my_volume 2、列出数据卷 使用 docker volume ls 命令可以列出所有的数据卷…...

Elixir语言的移动应用安全

Elixir语言的移动应用安全解析 引言 在当今的数字化时代&#xff0c;移动应用已经成为我们日常生活中不可或缺的一部分。从购物、社交到在线银行&#xff0c;几乎每一个生活领域都与移动应用紧密相连。然而&#xff0c;随着应用的普及&#xff0c;安全问题也随之而来。如何确…...

【科学技术部政务服务平台-用户注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…...

HTTP 教程 : 从 0 到 1 全面指南 教程【全文三万字保姆级详细讲解】

目录 HTTP 的请求-响应 HTTP 方法 HTTP 状态码 HTTP 版本 安全性 HTTP/HTTPS 简介 HTTP HTTPS HTTP 工作原理 HTTPS 作用 HTTP 与 HTTPS 区别 HTTP 消息结构 客户端请求消息 服务器响应消息 实例 HTTP 请求方法 各个版本定义的请求方法 HTTP/1.0 HTTP/1.1 …...

【LeetCode 热题100】139:单词拆分(动态规划全解析+细节陷阱)(Go语言版)

&#x1f680; LeetCode 热题 139&#xff1a;单词拆分&#xff08;Word Break&#xff09;| 动态规划全解析细节陷阱 &#x1f4cc; 题目描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请判断 s 是否可以由字典中出现的单词拼接成。 说明&#xff1a;不要求字典…...

2025年招投标行业的深度变革:洞察趋势,把握未来

2025年&#xff0c;随着政府工作报告对招投标行业的一系列改革措施的提出&#xff0c;整个行业正面临一场前所未有的深度变革。这些政策旨在推动全国统一大市场的建设、加速数字化转型、促进绿色低碳发展&#xff0c;并强化风险防控。在这场变革中&#xff0c;企业不仅要适应新…...

树莓派学习专题<3>:使能VNC远程桌面与VNC文件传输

树莓派学习专题&#xff1c;3&#xff1e;&#xff1a;使能VNC远程桌面与VNC文件传输 1. 配置VNC2. 使用VNC viewer连接到树莓派3. 使用VNC viewer传输文件 1. 配置VNC 在终端或SSH中&#xff0c;使用如下命令打开树莓派系统配置项&#xff1a; sudo su raspi-config以上两项…...

AI烘焙大赛中的算法:理解PPO、GRPO与DPO最简单的方式

&#x1f9e0; 向所有学习者致敬&#xff01; “学习不是装满一桶水&#xff0c;而是点燃一把火。” —— 叶芝 我的博客主页&#xff1a; https://lizheng.blog.csdn.net &#x1f310; 欢迎点击加入AI人工智能社区&#xff01; &#x1f680; 让我们一起努力&#xff0c;共创…...

qt自定义信号槽需要注意的事项

在 Qt 中&#xff0c;自定义信号和槽是与事件和对象交互的核心机制之一。创建自定义信号和槽时&#xff0c;有几个重要事项需要注意&#xff0c;以确保它们能够正确工作。以下是一些需要注意的关键点&#xff1a; 1. 信号和槽的声明 信号声明&#xff1a;信号应该在 signals …...

OpenCV--图像轮廓检测

在图像处理与计算机视觉领域&#xff0c;轮廓检测是一项极为关键的技术。轮廓作为物体边界的重要表征&#xff0c;承载了图像中物体的形状、尺寸和位置等关键信息。通过轮廓检测&#xff0c;我们能够提取出图像中物体的轮廓&#xff0c;为后续的物体识别、图像分割、形状分析等…...

从搜索丝滑过渡到动态规划的学习指南

搜索&动态规划 前言砝码称重满分代码及思路solution 1&#xff08;动态规划&#xff09;solution 2&#xff08;BFS&#xff09; 跳跃满分代码及思路solution 1(动态规划)solution 2 (BFS) 积木画满分代码及思路动态规划思路讲解solution 前言 本文主要是通过一些竞赛真题…...

通用文字识别技术的出现,深刻改变信息的处理方式

在数字化浪潮席卷全球的今天&#xff0c;文字作为人类文明最基础的载体&#xff0c;正经历着一场前所未有的技术革命。通用文字识别&#xff08;OCR&#xff0c;Optical Character Recognition&#xff09;技术已经从简单的"图片转文字"工具&#xff0c;进化为能够理…...

linux 下du 和 ls-alh 的区别

我一直以为du -m 可以显示文件大小。发现不对。正确的做法你是用ls -alh 来使用...

【k8s学习之CSI】理解 LVM 存储概念和相关操作

鸟哥的 Linux 私房菜 – Quota, Software RAID, LVM, iSCSI 0 | 理解 vg 相关概念 在 Linux LVM&#xff08;逻辑卷管理&#xff09; 中&#xff0c;以下是 partition&#xff08;分区&#xff09;、PV&#xff08;物理卷&#xff09;、VG&#xff08;卷组&#xff09;、LV&am…...

【分享开发笔记,赚取电动螺丝刀】使用STM32F103的hal库,采用PWM+DMA发送方式驱动WS2812的RGB彩灯

简单和大家介绍一下本文章的主要内容&#xff1a;使用STM32F103C8最小系统板&#xff0c;使用STM32 cubeMX 6.14版本生成底层的驱动库、结合定时器的PWM 输出功能、使用DMA发送数据的 方式&#xff0c;驱动WS2812 的RGB三色灯。 本次小的DIY所需的物料&#xff1a;stm32f103c8…...

CubeMX配置STM32VET6实现网口通信(无操作系统版-附源码)

下面是使用CubeMX配置STM32F407VET6&#xff0c;实现以太网通讯&#xff08;PHY芯片为LAN8720&#xff09;的具体步骤总结&#xff1a; 一、硬件连接方式&#xff1a; 硬件原理图&#xff1a; 使用外部晶振为PHY芯片提供时钟。 STM32F407VET6 与 LAN8720 采用 RMII 模式连接。…...

一种反激式开关电源设计流程

引&#xff1a;随着生产和技术的发展&#xff0c;对环保和能源的要求也越来越高&#xff0c;开关电源的应用也越来越广泛&#xff0c;开关电源电路结构种类繁多&#xff0c;包括单端转换器和双端转换器。本文介绍一种利用反激式变换电路实现5V开关电源的设计方法&#xff0c;以…...

数据结构实验3.2:链栈的基本操作与括号匹配问题

文章目录 一&#xff0c;问题描述二&#xff0c;基本要求三&#xff0c;算法分析&#xff08;一&#xff09;链栈的存储结构设计&#xff08;二&#xff09;链栈基本操作的时间复杂度分析&#xff08;三&#xff09;括号匹配算法分析 四&#xff0c;示例代码五&#xff0c;实验…...

一周学会Pandas2 Python数据处理与分析-NumPy算术运算和统计计算

锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 算术运算 数组的灵魂就在于可以进行批量的运算而不是要在循环里面进行元素的运算&#xff1a; 示例&#xff1a; …...

2011年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析

2011年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析 全国大学生数学建模竞赛(China Undergraduate Mathematical Contest in Modeling)是国家教委高教司和中国工业与应用数学学会共同主办的面向全国大学生的群众性科技活动,目的在于激励学生学习数学的积极性,提高学…...

科普:GBDT与XGBoost比较

本文不去讲GBDT与XGBoost算法的原理及算法本身&#xff0c;而是从应用者的角度&#xff0c;对二者比较&#xff0c;以便选择。 XGBoost是GBDT的“工程化增强版”&#xff0c;在保持Boosting核心思想的同时&#xff0c;通过数学优化&#xff08;二阶导数、正则化&#xff09;和工…...

大数据技术之 Scala(5)

以下是今天学习的知识点与代码测试&#xff1a; 一、不可变数组与可变数组的转换 说明 arr1.toBuffer //不可变数组转可变数组arr2.toArray //可变数组转不可变数组 arr2.toArray 返回结果才是一个不可变数组&#xff0c;arr2 本身没有变化arr1.toBuffer 返回结果才是一个可变…...