系列文章目录

数据结构之ArrayList_arraylist o(1) o(n)-CSDN博客

数据结构之LinkedList-CSDN博客

数据结构之栈_栈有什么方法-CSDN博客

数据结构之队列-CSDN博客

数据结构之二叉树-CSDN博客

数据结构之优先级队列-CSDN博客

常见的排序方法-CSDN博客

数据结构之Map和Set-CSDN博客


目录

系列文章目录

前言

一、二叉搜索树

1. 二叉搜索树的性质

2. 二叉搜索树的查询性能

二、AVL树

1. AVL 树的性质

2. AVL树的节点定义

3. AVL树节点的插入

 4. AVL树的验证

1. 验证其为二叉搜索树

2. 验证其为平衡树

5. AVL树的性能分析

三、红黑树

1. 红黑树的性质

2. 红黑树的节点定义

3. 红黑树节点的插入

4. 红黑树的验证

四、AVL树和红黑树的比较


前言

本文介绍了两种自平衡二叉搜索树:AVL树和红黑树。AVL树通过保持左右子树高度差不超过1来实现严格平衡,其查询效率为O(logN),但在插入删除时需要频繁旋转调整。红黑树通过颜色规则(无连续红节点、路径黑节点数相同)实现近似平衡,最长路径不超过最短路径两倍,虽然查询效率略低于AVL树,但插入删除时旋转次数较少,实际应用更广泛。文章详细阐述了两者的性质、节点结构、插入操作(含平衡调整逻辑)及验证方法,并通过性能对比说明AVL树适合读多写少场景,红黑树更适合频繁修改的场景。


一、二叉搜索树

1. 二叉搜索树的性质

二叉搜索树中的左孩子的值都小于根节点的值,右孩子的值都大于根节点的值;

二叉搜索树的中序遍历是一个有序数组;

2. 二叉搜索树的查询性能

如果在二叉搜索树中连续插入的值都比之前插入的值大,那么二叉搜索树会变成一棵右单树,查询效率就会从原来的 O(logN) 退化成 O(N);

为了保证二叉搜索树的查询效率,就引入了高度平衡的二叉搜索树,即 AVL 树;

二、AVL树

1. AVL 树的性质

AVL树是一棵高度平衡的二叉搜索树,即左右子树的高度差不超过 1;

2. AVL树的节点定义

val 表示节点的值;

bf 表示平衡因子,计算方法为 右树的高度 - 左树的高度

left 表示左子树;

right 表示右子树;

parent 表示父亲节点;

public class AVLTree {static class TreeNode{public int val;public int bf;public TreeNode left;public TreeNode right;public TreeNode parent;public TreeNode(int val){this.val = val;}}// 二叉搜索树的属性及方法// ......
}

3. AVL树节点的插入

root 表示 AVL 树的根节点;

insert(int val): boolean 在 AVL 树中插入节点;

思路:

1. 如果树为空,那么新插入的节点就是树的根节点;

2. 查找

节点的插入方式和二叉搜索树相同,定义 cur 找要插入节点的位置,parent 指向 cur 的父节点;

如果 cur 的值小于 val,去右子树找,如果 cur 的值大于 val,去左子树找找,如果 cur 的值等于 val,说明节点已经存在,不能进行插入,返回 false 即可; 

3. 插入

如果 cur 为空,表示找到了插入位置,如果节点的值小于 parent 的值,插入到 parent 左边,如果节点的值大于 parent 的值,插入到 parent 的右边,再让 cur 重新指向新插入的节点;

4. 修改平衡因子

如果 cur 是 parent 的左子树,说明插入的节点在 parent 左边,左子树的高度增加了,因此 parent 的平衡因子减 1;

如果 cur 是 parent 的右子树,说明插入的节点在 parent 右边,右子树的高度增加了,因此 parent 的平衡因子加 1;

5. 判断平衡因子

如果修改完 parent 的平衡因子等于 0,表示 parent 这棵树已经平衡了,同时 0 不会影响整棵树的平衡,直接返回 true 即可;

如果修改完 parent 的平衡因子等于 1 或者 -1,表示 parent 平衡,但是可能会影响整棵树的平衡,需要继续向上调整平衡因子,因此 cur 指向 parent,parent 重新指向 cur 的父节点,继续向上调整;

6. 树的调整

继续向上调整的过程中,如果修改完 parent 的平衡因子等于 2 或者 -2,表示 parent 这棵树已经不平衡了,此时需要进行旋转操作,来使得树重新达到平衡;

如果 parent 的平衡因子等于 2,并且 cur 的平衡因子等于 1,表示 parent 和 cur 子树的右子树高度高,此时通过左旋 parent 使树重新达到平衡;

    private void rotateLeft(TreeNode parent){TreeNode subR = parent.right;TreeNode subRL = subR.left;// 修改四个指向parent.right = subRL;subR.left = parent;if(subRL != null){subRL.parent = parent;}// 修改 parent 的父节点之前,保存 parent 的父节点TreeNode pParent = parent.parent;parent.parent = subR;if(root == parent){root = subR;root.parent = null;}else{if(pParent.left == parent){pParent.left = subR;}else{pParent.right = subR;}}subR.parent = pParent;subR.bf = 0;parent.bf = 0;}

如果 parent 的平衡因子等于 -2,并且 cur 的平衡因子等于 -1,表示 parent 和 cur 子树的左子树高度高,此时通过右旋 parent 使树重新达到平衡;

    private void rotateRight(TreeNode parent){TreeNode subL = parent.left;TreeNode subLR = subL.right;// 修改四个指向parent.left = subLR;subL.right = parent;if(subLR != null){subLR.parent = parent;}// 记录父节点的父节点,旋转完成会用到TreeNode pParent = parent.parent;parent.parent = subL;// 修改 subL 的指向if(root == parent){root = subL;root.parent = null;}else{if(pParent.left == parent){pParent.left = subL;}else{pParent.right = subL;}}subL.parent = pParent;// 修改平衡因子subL.bf = 0;parent.bf = 0;}

如果 parent 的平衡因子等于 2,并且 cur 的平衡因子等于 -1,表示 parent子树的右子树高度高,cur 子树的左子树高度高,此时通过右旋 cur 子树,降低 cur 左树的高度,再左旋 parent 子树,降低 parent 右树的高度,使树重新达到平衡;

    private void rotateRL(TreeNode parent){TreeNode subR = parent.right;TreeNode subRL = subR.left;int bf = subRL.bf;rotateRight(subR);rotateLeft(parent);if(bf == -1){parent.bf = 0;subRL.bf = 0;subR.bf = 1;}else if(bf == 1){parent.bf = -1;subRL.bf = 0;subR.bf = 0;}}

如果 parent 的平衡因子等于 -2,并且 cur 的平衡因子等于 1,表示 parent子树的左子树高度高,cur 子树的右子树高度高,此时通过左旋 cur 子树,降低 cur 右树的高度,再右旋 parent 子树,降低 parent 左树的高度,使树重新达到平衡;

    private void rotateLR(TreeNode parent){TreeNode subL = parent.left;TreeNode subLR = subL.right;int bf = subLR.bf;rotateLeft(subL);rotateRight(parent);if(bf == -1){parent.bf = 1;subL.bf = 0;subLR.bf = 0;}else if(bf == 1){subL.bf = -1;subLR.bf = 0;parent.bf = 0;}}

修改平衡因子需要从下往上依次修改,直到 parent 为空;

代码实现:

    public TreeNode root;public boolean insert(int val){// 1. 插入节点TreeNode node = new TreeNode(val);if(root == null){root = node;return true;}TreeNode parent = null;TreeNode cur = root;while(cur != null){if(cur.val < val){parent = cur;cur = cur.right;}else if(cur.val > val){parent = cur;cur = cur.left;}else{return false;}}// cur == nullif(parent.val < val){parent.right = node;}else{parent.left = node;}node.parent = parent;cur = node;// 2. 平衡因子的修改while(parent != null){if(cur == parent.left){parent.bf--;}else{parent.bf++;}if(parent.bf == 0){return true;}else if(parent.bf == 1 || parent.bf == -1){cur = parent;parent = parent.parent;}else{if(parent.bf == 2){if(cur.bf == 1){// 左单旋rotateLeft(parent);}else{// cur.bf == -1rotateRL(parent);}}else{ // parent.bf == -2if(cur.bf == -1){// 右单旋rotateRight(parent);}else{rotateLR(parent);}}return true;}}return true;}

 4. AVL树的验证

1. 验证其为二叉搜索树

利用二叉搜索树的性质:二叉搜索树的中序遍历是一个有序数组;

    // 中序遍历 - 有序表示当前树是二叉搜索树public void inOrder(TreeNode root){if(root == null){return;}inOrder(root.left);System.out.print(root.val + " ");inOrder(root.right);}

2. 验证其为平衡树

 如果每一棵子树都是平衡树,则这棵树是平衡树;

    public int getHeight(TreeNode root){if(root == null) return 0;int left = getHeight(root.left);if(left == -1) return -1;int right = getHeight(root.right);if(right == -1) return -1;if(Math.abs(left - right) > 1) return -1;return Math.max(left, right) + 1;}

5. AVL树的性能分析

AVL树是一个高度绝对平衡的二叉搜索树,查询的时间复杂度为O(longN);

当时AVL树插入或者删除节点的时候就会涉及到大量的旋转,性能比较低;

因此 AVL 树适用于查询数据,并且这些数据不会被经常修改;

三、红黑树

1. 红黑树的性质

  • 1. 每个节点 不是红色就是黑色;
  • 2. 根节点是黑色的;
  • 3. 如果一个节点是红色的,则它的两个孩子节点是黑色的(没有两个连续的红色节点);
  • 4. 对于每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点;
  • 5. 每个叶子节点都是黑色的(叶子节点指的是空节点);

2. 红黑树的节点定义

left 表示当前节点的左子树;

right 表示当前节点的右子树;

parent 表示当前节点的父亲节点; 

val 表示当前节点的值;

color 表示当前节点的颜色;

RBTreeNode(int val):表示红黑树节点的构造方法;

注意:红黑树默认插入节点的颜色是红色的;

如果插入节点是黑色的,为了满足红黑树不同路径上具有相同数量黑色节点的性质,那么就需要在所有路径上都插入一个黑色节点,这些节点是没有意义的,因此默认节点是红色;

public class RBTree {static class RBTreeNode{public RBTreeNode left;public RBTreeNode right;public RBTreeNode parent;public int val;public COLOR color;public RBTreeNode(int val){this.val = val;// 节点默认的颜色为红色,因为如果插入黑色节点,会导致不同路径上黑色节点的数量不一样多,// 这样还需要插入额外的黑色节点,才能保持红黑树的性质this.color = COLOR.RED;}}// 红黑树的属性和方法// ......
}

3. 红黑树节点的插入

root 表示红黑树的根节点;

insert(int val): boolean 在红黑树中插入节点; 

思路:

1. 如果树为空,那么新插入的节点就是树的根节点,插入后将根节点的颜色置为黑色;

2. 查找

节点的插入方式和二叉搜索树相同,定义 cur 找要插入节点的位置,parent 指向 cur 的父节点;

如果 cur 的值小于 val,去右子树找,如果 cur 的值大于 val,去左子树找找,如果 cur 的值等于 val,说明节点已经存在,不能进行插入,返回 false 即可; 

3. 插入

如果 cur 为空,表示找到了插入位置,如果节点的值小于 parent 的值,插入到 parent 左边,如果节点的值大于 parent 的值,插入到 parent 的右边,再让 cur 重新指向新插入的节点;

4. 调整颜色

插入一个节点,如果此时插入节点的父亲节点也是红色的,那么就不能满足红黑树不能有两个连续红色节点的性质,因此为了解决这个问题,就需要对红黑树的颜色进行向上调整;

使用 grandFather 指向 parent 节点的父亲节点,uncle 指向 grandFather 的另外一个子节点;

如果 parent 是 grandFather 的左子树,分为以下三种情况处理:

情况 1:parent 为红色,uncle 指向 grandFather 的右子树,且颜色为红色

parent 和 uncle 调整为黑色,grandFather 调整为红色,如下所示:

调整完成后 cur 指向 grandFather,parent 指向 cur 的父亲节点; 

情况 2:parent 为红色,uncle 为黑色,grandFather 为黑色,cur 为 parent 的左子树

先右旋 grandFather,完成后 parent 颜色置为黑色,grandFather 颜色置为红色,如下图:

情况 3:parent 为红色,uncle 为黑色,grandFather 为黑色,cur 为 parent 的右子树
先左旋 parent,再交换 parent 和 cur 指向的位置,得到的情况和情况 2 是相同的,之后再按照情况的处理方式进行处理即可,如下图:

同理,如果 parent 是 grandFather 的左子树,也分为以下三种情况处理:

情况 1:parent 为红色,uncle 指向 grandFather 的左子树,且颜色为红色

parent 和 uncle 调整为黑色,grandFather 调整为红色,如下所示:

调整完成后 cur 指向 grandFather,parent 指向 cur 的父亲节点; 

情况 2:parent 为红色,uncle 为黑色,grandFather 为黑色,cur 为 parent 的右子树

先左旋 grandFather,完成后 parent 颜色置为黑色,grandFather 颜色置为红色,如下图:

情况 3:parent 为红色,uncle 为黑色,grandFather 为黑色,cur 为 parent 的左子树
先右旋 parent,再交换 parent 和 cur 指向的位置,得到的情况和情况 2 是相同的,之后再按照情况的处理方式进行处理即可,如下图:

5. 处理根节点

向上调整颜色完成后,根节点有可能会被调整为红色,这是要重新把根节点的颜色调整为黑色,返回 true; 

    public RBTreeNode root;public boolean  insert(int val){RBTreeNode node = new RBTreeNode(val);if(this.root == null){this.root = node;this.root.color = COLOR.BLACK;return true;}RBTreeNode cur = root;RBTreeNode parent = null;while(cur != null){if(cur.val < val){parent = cur;cur = cur.right;}else if(cur.val > val){parent = cur;cur = cur.left;}else{return false;}}// cur == null,找到了应该插入的位置if(parent.val < val){parent.right = node;}else{parent.left = node;}node.parent = parent;cur = node;// 修改颜色while(parent != null && parent.color == COLOR.RED){RBTreeNode grandFather = parent.parent;if(grandFather.left == parent){RBTreeNode uncle = grandFather.right;// 情况 1if(uncle != null && uncle.color == COLOR.RED){parent.color = COLOR.BLACK;uncle.color = COLOR.BLACK;grandFather.color = COLOR.RED;cur = grandFather;parent = cur.parent;}else{// parent.color == COLOR.BLANK || uncle.color == COLOR.BLANK// 情况 3:if(parent.right == cur){// 左旋rotateLeft(parent);RBTreeNode tmp = parent;parent = cur;cur = tmp;}// 情况 2 grandFather.color = COLOR.BLANK uncle.color == COLOR.BLANKrotateRight(grandFather);parent.color = COLOR.BLACK;grandFather.color = COLOR.RED;}}else{// grandFather.right = parentRBTreeNode uncle = grandFather.left;// 情况 1:if(uncle != null && uncle.color == COLOR.RED){parent.color = COLOR.BLACK;uncle.color = COLOR.BLACK;grandFather.color = COLOR.RED;cur = grandFather;parent = cur.parent;}else{// parent.color == COLOR.BLANK || uncle.color == COLOR.BLANK// 情况 3:if(parent.left == cur){rotateRight(parent);RBTreeNode tmp = parent;parent = cur;cur = tmp;}// 情况 2:rotateLeft(grandFather);grandFather.color = COLOR.RED;parent.color = COLOR.BLACK;}}}this.root.color = COLOR.BLACK;return true;}

4. 红黑树的验证

验证红黑树分两步:

第一步,验证其为二叉搜索树,采用中序遍历的方式

    // 第一步:验证是否为二叉搜索树public void inOrder(RBTreeNode root){if(root == null) return;inOrder(root.left);System.out.print(root.val + " ");inOrder(root.right);}

第二步,验证红黑树的性质:

  • 根节点为黑色;
  • 没有连续的红色节点;
  • 每条路径上的黑色节点的数量是相同的; 
    public boolean isRBTree(RBTreeNode root, int pathBlackNum, int blackNum){if(root == null) {return true;}// 验证红黑树的性质,分为三个性质进行验证// 第一步:验证根节点是否为黑色if(root.color == COLOR.RED){System.out.println("根节点为红色!");return false;}boolean flag = false;// 第二步:验证是否存在连续的两个红色的节点flag = checkRedNode(root);if(!flag) return false;// 第三步:验证是否每条路径上的黑色节点数量都相同flag = checkBlackNodeNum(root, pathBlackNum, blackNum);if(!flag) return false;return true;}private boolean checkRedNode(RBTreeNode root){if(root == null){return true;}// 遍历二叉树,如果遇到红色的节点,看一下它的父节点是否为红色即可if(root.color == COLOR.RED){RBTreeNode parent = root.parent;if(parent.color == COLOR.RED){System.out.println("连续两个红色的节点!");return false;}}return checkRedNode(root.left) && checkRedNode(root.right);}private boolean checkBlackNodeNum(RBTreeNode root, int pathBlackNum, int blackNum) {if(root == null){if(pathBlackNum == blackNum){return true;}System.out.println("路径上的黑色节点数量不相同!");return false;}if(root.color == COLOR.BLACK){pathBlackNum++;}return checkBlackNodeNum(root.left, pathBlackNum, blackNum) &&checkBlackNodeNum(root.right, pathBlackNum, blackNum);}

四、AVL树和红黑树的比较

 AVL树和红黑树都是二叉搜索树,也都是二叉平衡树;

AVL树追求绝对的高度平衡,即左右子树的高度差不超过 1;

红黑树不追求绝对平衡,保证每条路径上的黑色节点的数量相同即可且没有连续的红色节点,即最长路径上的长度是最短路径长度的二倍;

AVL树在插入和删除节点的时候,需要大量的旋转,不适合进行频繁的插入和删除;

红黑树在插入和删除节点的时候,减少了旋转的次数,因此在实际应用中更多;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/913377.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/913377.shtml
英文地址,请注明出处:http://en.pswp.cn/news/913377.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Maven引入第三方JAR包实战指南

要将第三方提供的 JAR 包引入本地 Maven 仓库&#xff0c;可通过以下步骤实现&#xff08;以 Oracle JDBC 驱动为例&#xff09;&#xff1a;&#x1f527; 方法 1&#xff1a;使用 install:install-file 命令&#xff08;推荐&#xff09;定位 JAR 文件 将第三方 JAR 包&#…

JavaSE -- 泛型详细介绍

泛型 简介 集合存储数据底层是利用 Object 来接收的&#xff0c;意思是说如果不对类型加以限制&#xff0c;所有数据类型柔和在一起&#xff0c;这时如何保证数据的安全性呢&#xff08;如果不限制存入的数据类型&#xff0c;任何数据都能存入&#xff0c;当我们取出数据进行强…

使用 Python 实现 ETL 流程:从文本文件提取到数据处理的全面指南

文章大纲&#xff1a; 引言&#xff1a;什么是 ETL 以及其重要性 ETL&#xff08;提取-转换-加载&#xff09;是数据处理领域中的核心概念&#xff0c;代表了从源数据到目标系统的三个关键步骤&#xff1a;**提取&#xff08;Extract&#xff09;**数据、**转换&#xff08;Tra…

selenium基础知识 和 模拟登录selenium版本

前言 selenium框架是Python用于控制浏览器的技术,在Python爬虫获取页面源代码的时候,是最重要的技术之一,通过控制浏览器,更加灵活便捷的获取浏览器中网页的源代码。 还没有安装启动selenium的同志请先看我的上一篇文章进行配置启动 和 XPath基础 对selenium进行浏览器和驱动…

JS 网页全自动翻译v3.17发布,全面接入 GiteeAI 大模型翻译及自动部署

两行 js 实现 html 全自动翻译。 无需改动页面、无语言配置文件、无 API Key、对 SEO 友好&#xff01; 升级说明 translate.service 深度绑定 GiteeAI 作为公有云翻译大模型算力支持translate.service 增加shell一键部署后通过访问自助完成GiteeAI的开通及整个接入流程。增加…

数据结构:数组:插入操作(Insert)与删除操作(Delete)

目录 插入操作&#xff08;Inserting in an Array&#xff09; 在纸上模拟你会怎么做&#xff1f; 代码实现 复杂度分析 删除操作&#xff08;Deleting from an Array&#xff09; 在纸上模拟一下怎么做&#xff1f; 代码实现 复杂度分析 插入操作&#xff08;Inserti…

Qt之修改纯色图片的颜色

这里以修改QMenu图标颜色为例,效果如下: MyMenu.h #ifndef MYMENU_H #define MYMENU_H#include <QMenu>class MyMenu : public QMenu { public:explicit MyMenu(QWidget *parent = nullptr);protected:void mouseMoveEvent(QMouseEvent *event) override; };#endif /…

uni-app实现单选,多选也能搜索,勾选,选择,回显

前往插件市场安装插件下拉搜索选择框 - DCloud 插件市场&#xff0c;该插件示例代码有vue2和vue3代码 是支持微信小程序和app的 示例代码&#xff1a; <template><view><!-- 基础用法 --><cuihai-select-search:options"options"v-model&quo…

【机器学习深度学习】 微调的十种形式全解析

目录 一、为什么要微调&#xff1f; 二、微调的 10 种主流方式 ✅ 1. 全参数微调&#xff08;Full Fine-tuning&#xff09; ✅ 2. 冻结部分层微调&#xff08;Partial Fine-tuning&#xff09; ✅ 3. 参数高效微调&#xff08;PEFT&#xff09; &#x1f538; 3.1 LoRA&…

信刻光盘安全隔离与文件单向导入/导出系统

北京英特信网络科技有限公司成立于2005年&#xff0c;是专业的数据光盘摆渡、刻录分发及光盘存储备份领域的科技企业&#xff0c;专注为军队、军工、司法、保密等行业提供数据光盘安全摆渡、跨网交换、档案归档检测等专业解决方案。 公司立足信创产业&#xff0c;产品国产安全可…

Python-标准库-os

1 需求 2 接口 3 示例 4 参考资料 在 Python 中&#xff0c;os&#xff08;Operating System&#xff09;模块是一个非常重要的内置标准库&#xff0c;提供了许多与操作系统进行交互的函数和方法&#xff0c;允许开发者在 Python 程序中执行常见的操作系统任务&#xff0c;像文…

OpenCV CUDA模块设备层-----在 GPU 上执行类似于 std::copy 的操作函数warpCopy()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 OpenCV 的 CUDA 模块&#xff08;cudev&#xff09; 中的一个设备端内联模板函数&#xff0c;用于在 GPU 上执行类似于 std::copy 的操作&#xff…

Vue Router 中$route.path与 params 的关系

1. params 参数的本质&#xff1a;路径的动态片段在 Vue Router 中&#xff0c;params 参数是通过路由配置的动态路径片段定义的&#xff0c;例如&#xff1a;// 路由配置{ path: /user/:id, component: User }当访问/user/123时&#xff0c;/user/123是完整的路径&#xff0c;…

React 极简响应式滑块验证组件实现,随机滑块位置

&#x1f3af; 滑块验证组件 (Slider Captcha) 一个现代化、响应式的滑块验证组件&#xff0c;专为 React 应用设计&#xff0c;提供流畅的用户体验和强大的安全验证功能。 ✨ 功能特性 &#x1f3ae; 核心功能 智能滑块拖拽 – 支持鼠标和触摸屏操作&#xff0c;响应灵敏随…

STM32第十六天蓝牙模块

一&#xff1a;蓝牙模块HC-05 1&#xff1a;硬件引脚配置&#xff1a; | 标号 | PIN | 说明 | |------|-------|---------------------------------------| | 1 | START | 状态引出引脚&#xff08;未连接/连接输出信号时&#xff09; |…

时序数据库IoTDB用户自定义函数(UDF)使用指南

1. 编写UDF时序数据库IoTDB为用户提供了编写UDF的JAVA API&#xff0c;用户可以自主实现UDTF&#xff08;用户自定义转换函数&#xff09;类&#xff0c;IoTDB将通过类加载机制装载用户编写的类。Maven依赖如果使用Maven&#xff0c;可以从Maven库中搜索以下依赖&#xff0c;并…

Linux国产与国外进度对垒

Linux国产与国外进度对垒 引言国产Linux的发展现状国外Linux的发展现状技术对比国产Linux的挑战与机遇国外Linux的优势与局限结论 引言 简述Linux在全球操作系统市场中的地位国产Linux的发展背景与意义国外主流Linux发行版的现状 国产Linux的发展现状 主要国产Linux发行版介…

Jenkins-Email Extension 插件插件

Editable Email Notification Editable Email Notification 是 Jenkins 的 Email Extension 插件的核心功能&#xff0c;用于自定义邮件通知&#xff0c;包括邮件主题、内容、收件人、发件人等 属性 1.Project From 项目发件人&#xff0c;设置邮件的发件人地址 **注意&…

windows系统下将Docker Desktop安装到除了C盘的其它盘中

windows系统下安装docker会自动安装到C盘&#xff0c;可以采用下面的方法将其安装到其它盘中1、先下载Docker Desktop安装程序Docker Desktop Installer.exe&#xff0c;比如你下载到了C:\Users\YourUsername\Downloads 文件夹中。 2、打开 PowerShell 进入C:\Users\YourUser…

视频工具箱 1.1.1 |小而美的视频处理工具,支持多种常用功能

VideoTools是一款基于FFmpeg的小而美的视频处理工具&#xff0c;专为需要快速高效地进行视频编辑的用户设计。这款工具无需安装&#xff0c;体积仅约200KB&#xff0c;提供了视频压缩、格式转换、转GIF、修改分辨率、加速播放以及音频提取等多种常用功能。其用户界面简洁直观&a…