C++数据结构:B树

目录

一. 常见的搜索结构

二. B树的概念

三. B树节点的插入和遍历

3.1 插入B树节点

3.2 B树遍历

四. B+树和B*树

4.1 B+树

4.2 B*树

五. B树索引原理

5.1 索引概述

5.2 MyISAM

5.3 InnoDB

六. 总结


一. 常见的搜索结构

表示1为在实际软件开发项目中,常用的查找结构和方法,包括顺序查找、二分查找、二叉搜索树、平衡二叉树、哈希表等,这几种查找方法和数据结构,都适合于内查找(将数据加载到内存中查找)。

搜索结构数据要求时间复杂度
顺序查找无要求O(N)
二分查找顺序排序O(logN)
二叉搜索树无要求O(N)
平衡二叉树无要求O(logN)
哈希表无要求O(1)

如果数据量极大,内存无法存放时,就需要将数据存储在磁盘当中,而CPU访问磁盘的速度要远远低于访问内存的速度,假设O(1)的时间复杂度下要执行2次访问,O(logN)的时间复杂度下要执行30次访问。如果对内存数据进行访问,因为访问内存速度相对较快,所有我们可以认为O(1)和O(logN)时间复杂度算法的性能是一致的。但是如果是对于磁盘上的数据的访问,由于磁盘数据访问的效率较低,因此O(1)和O(logN)差别会很大。

采用二叉搜索树检索磁盘数据的缺陷为:

  • 二叉搜索树查找的时间复杂度为O(logN),磁盘IO效率低,O(logN)的时间复杂度相对于O(1)会很大程度上降低性能。

但是,哈希查找的时间复杂度是O(1),为什么哈希也不适用于对磁盘数据的检索呢?这是因为哈希的有这样的缺陷:

  • 在极端情况下,哈希表中会产生大量的哈希冲突,查找的时间复杂度会接近O(N)。
  • 虽然很多时候当哈希冲突达到一定数量时,在哈希散列中会由挂单链表改为挂红黑树,但红黑树查找的时间复杂度依旧是O(logN)。

为了解决平衡二叉树和哈希表无法很好的应对内存数据查找的情况,B树被创造和出来,B树适用于对磁盘中大量的数据进行检索,当然B树也能够在内存在查找数据,但效果就不如哈希和平衡二叉树。

由于B树/B+树适用于检索磁盘中大量数据的性质,经常被用于作为数据库的底层检索结构。

二. B树的概念

B树是一种适合外查找的平衡多叉树,一颗m阶的B树,是一颗m路的二叉搜索树,一颗B树要么为空树,要么满足如下几个条件:

  1. 根节点至少有两个孩子节点。
  2. 分支节点(非叶子节点)应当有K-1个键值和K个孩子节点,其中ceil(m/2)\leqslant K\leqslant M,其中ceil为向上取整函数。
  3. 所有叶子节点都在同一层。
  4. 每个节点中的键值都是自小到大升序排序的,键值Key表示子树的阈值划分。
  5. 对于任意一个节点,孩子节点的数目总是比键值多一个。

图2.1就是一颗3阶B树,注意观察其根节点,两个键值为50和100,根节点的第一个孩子节点键值全部小于50,第二个孩子节点的键值位于(51,100)之间,第三个孩子节点键值大于100,这就是键值Key的阈值划分功能。

B树检索与二叉搜索树的检索类似,假设我们要在图2.1所示的B树中检索99,先从根节点开始找起,对比待查找的值和键值的大小,发现其位于(50,100)范围内,这样就向下遍历查找p2子树,在p2子树的键值中找到了键值99,检索完成。

图2.1 3阶B树

三. B树节点的插入和遍历

3.1 插入B树节点

由于B树的插入操作过于抽象,因此直接上实例,在示例中讲解B树节点插入的具体操作。假设依次将std::vector<int> v = { 53,139,75,49,145,36,50,47,101}插入到3阶B树中。为了方便插入操作,我们在申请B树节点空间的时候,阶数为M,就为键值申请M个空间,为孩子节点申请M+1个空间,这样做的目的是方便插入时数据挪动,以及后面的分裂操作

① 插入53

53是B树插入的第一个节点,因此直接将其插入到根节点的第一个键值位置处即可。如果3.1所示,插入53后,有一个B树根节点,这个根节点附带有两个孩子节点nullptr。这里的根节点也是叶子节点,注意B树插入新节点一定是向叶子节点插入的。

图3.1 插入B树的第一个节点53

② 插入139

139大于53,且插入后根节点(叶子结点)中键值的数目不超过M-1,因此只需将139至于53的后面,并且带入null子节点即可。

图3.2 插入第二个节点139后的B树结构

③ 插入75

75位于53和139之间,所以第一步要现将75插入到root节点的这两个值之间。但是,插入75后root节点就有了3个键值,这样就不符合B树的结构要求,需要进行分裂。

分裂操作的步骤为:

  1. 取中间位置mid = M/2下标处为分界线,创建一个兄弟节点brother,将下标位于[mid+1,M)的键值及其左右孩子都拷贝到brother节点中去(设下标为键值相同的孩子节点为左孩子,比键值下标大1的孩子节点称为右孩子)。
  2. 将mid处的键值交给其父亲节点,如果没有父亲节点节创建父亲节点,父亲节点的其中两个孩子节点就包含原先发生分裂的节点以及分裂出的节点brother。
图3.3 插入第三个节点75后的结构及B树的分裂操作

④ 插入49

首先检索节点插入的位置,发现49小于根节点root的第一个键值,因此找到n1节点,n1节点为叶子节点可以执行插入操作,49小于第一个节点53,所以应当将53向后移动一位并将49设置为n1节点的第一个键值。

图3.4 插入B树第四个节点49

 ⑤ 插入145

首先检索插入数据的叶子节点,根节点只有一个键值75,145大于75,向n2节点查找,n2为叶子节点可以执行插入操作,将145插入到139后面,插入过后键值个数少于阶数M,不用分裂。

图3.5 插入B树第五个节点49

⑥ 插入36

查找36的插入位置应该为图3.5中的n1节点,将35插入n1后n1有3个键值需要进行分裂,兄弟节点取走53,49向上交给n1的父亲节点,分裂出的兄弟节点要作为root节点的一个孩子节点。

图3.6 插入新节点36及分裂操作

⑦ 插入50 

直接找到n2节点,插入到键值53之前即可。

图3.7 插入新节点53

⑧ 插入47

 插入到n1节点46的后面即可。

图3.8 插入新节点47

⑨ 插入101

先初步执行插入操作,即101插入到n3节点的第一个键值位置处,插入后n3节点的键值数量达到了阶数M,要执行分裂操作。然而分裂后将mid处键值交给父亲节点(root)管理后,root的键值数量也达到了阶数M,需要进一步分裂,更新root。

图3.9 插入新节点101

3.2 B树遍历

B树是一种特殊的搜索树,如果按照中选遍历,那么理应得到升序的一组数据,B树遍历的方法与普通的二叉搜索树中序遍历并没有本质区别,区别在于M路遍历和双路遍历。图3.10为二叉搜索树的遍历流程图,遍历得到升序排序结果。

图3.10 B树前序遍历的递归路径图

代码3.1:插入B树节点和前序遍历B树

#include <iostream>// B树节点,K为索引数据类型,M为最大阶数
template<class K, size_t M>
struct BTreeNode
{// 存储键值和孩子节点的一维数组// K _key[M - 1];// BTreeNode<K, M> _sub[M];// 为了方便后续的分裂和插入操作,多开辟一个空间K _key[M];BTreeNode<K, M>* _sub[M + 1];BTreeNode<K, M>* _parent;   // 父亲节点size_t _n;   // 键值个数// 构造函数BTreeNode(): _parent(nullptr), _n(0){// 键值全部清零,孩子节点全部为空for (size_t i = 0; i < M; ++i){_key[i] = K();_sub[i] = nullptr;}_sub[M] = nullptr;}
};template<class K, size_t M>
class BTree
{typedef BTreeNode<K, M> Node;   // B树节点类型重定义
public:// 插入位置查找函数std::pair<Node*, int> Find(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){// 在本层中,查找大于key的键值,如果找到这样的键值或者走到了最后一个键值// 那么就到下一层去查找,如果找到与key相同的键值,那么就直接返回该位置对应pairsize_t i = 0;while (i < cur->_n){// 键值按照升序排序,逐个向后查找即可if (key > cur->_key[i]) {++i;}else if (key < cur->_key[i]){break;}else   // 存在相等就直接返回{return std::make_pair(cur, i);}}parent = cur;cur = cur->_sub[i];}return std::make_pair(parent, -1);}// 在一个B树节点值插入新键值的函数void InsertKey(Node* parent, const K& key, Node* child){int end = parent->_n - 1;while (end >= 0){if (parent->_key[end] > key){// 将大于key的键值及其对应的右孩子节点全部向后移动一位parent->_key[end + 1] = parent->_key[end];parent->_sub[end + 2] = parent->_sub[end + 1];--end;}else{break;}}// 将新的key值插入到end+1位置处,并引入右孩子节点parent->_key[end + 1] = key;parent->_sub[end + 2] = child;++parent->_n;}// 新节点(键值)插入函数bool Insert(const K& key){// 特殊情况:当前B树根节点为空,插入的是第一个节点if (_root == nullptr){_root = new Node;_root->_key[0] = key;_root->_n++;return true;}// 查找要插入节点的位置std::pair<Node*, int> ret = Find(key);// 如果对应ret.second>=0,那说明key已经在B树中存在// B树不允许冗余,因此直接返回falseif (ret.second >= 0){return false;}Node* parent = ret.first;Node* child = nullptr;K newKey = key;// 向上插入,满足条件就分裂while (true){InsertKey(parent, newKey, child);if (parent->_n <= M - 1){return true;}else   // 需要进行分裂操作{size_t mid = M / 2;   // 中间节点// 将中间mid之后的键值全部交给新创建的brother节点Node* brother = new Node;size_t j = 0;for (size_t i = mid + 1; i < M; ++i){// 将key及其左孩子交给brother节点brother->_key[j] = parent->_key[i];brother->_sub[j] = parent->_sub[i];// 如果左孩子节点不为空,那么就要跟新其父亲为brotherif (parent->_sub[i] != nullptr){parent->_sub[i]->_parent = brother;}// 将parent节点中被挪走的key和sub清空parent->_key[i] = K();parent->_sub[i] = nullptr;++j;}// 将最后一个右孩子节点插入到brother节点中brother->_sub[j] = parent->_sub[M];if (parent->_sub[M] != nullptr){parent->_sub[M]->_parent = brother;}parent->_sub[M] = nullptr;// 更新键值个数,这里parent键值个数减去brother->_n + 1,+1是因为要把mid子节点交给父节点brother->_n = j;parent->_n -= (brother->_n + 1);K midKey = parent->_key[mid];parent->_key[mid] = K();if (parent == _root){_root = new Node;_root->_key[0] = midKey;_root->_sub[0] = parent;_root->_sub[1] = brother;parent->_parent = _root;brother->_parent = _root;_root->_n++;return true;}else{newKey = midKey;parent = parent->_parent;brother->_parent = parent;child = brother;}}}return true;}void _InOrder(Node* root){if (root == nullptr){return;}// 依次遍历每个节点的左孩子for (size_t i = 0; i < root->_n; ++i){_InOrder(root->_sub[i]);std::cout << root->_key[i] << " ";}// 遍历最后一个右孩子节点_InOrder(root->_sub[root->_n]);}// 中序函数void InOrder(){// 子函数_InOrder(_root);}private:Node* _root = nullptr;
};

四. B+树和B*树

4.1 B+树

B+树是在B树上优化了的多路平衡搜索二叉树,相比于B树,B+树进行了以下几点优化:

  1. 每个节点的键值数量和孩子节点数量相同。
  2. 孩子节点指针p[i]指向的子B树键值范围位于 [ k[i], k[i+1] ) 之间。
  3. 所有存储了有效键值的节点都在叶子节点上。
  4. 所有叶子节点都被连接了起来。
图4.1 B+树的结构

B+树的节点插入,与B树类似,同样由于其过于抽象,本文以具体的实例来展示B+树节点插入的过程,假设要将std::vector<int> v = { 53,139,75,49,145,36,101 }插入到阶数M=3的B+树中去,插入的流程及操作如下:

① 插入53

插入的第一个节点,首先创建两层B+树节点,一层为根节点,一层为叶子节点,在根节点和叶子节点的第一个键值位置处,插入元素53。和B树一样,如果阶数为M,就为键值和孩子节点都多开辟一个空间,以方便数据挪到和节点分裂。

图4.2 向B+树中插入第一个数据

② 插入139

首先检索插入位置,发现139大于根节点中唯一一个键值53,因此向下遍历找到n1,将新数据插入到53后面,节点中键值个数尚未达到阶数,不需要分裂。

图4.3 向B+树中插入139

③ 插入75

检索到75应该插入子节点n1中,139向后挪一个单位,75插入到53和139之间,以保证键值升序。

图4.4 向B+树中插入75

④ 插入49

首先查找可以插入49的叶子节点,检索到插入位置为第一个键值位置,因此要更新其父亲节点中对应位置的索引值,这样root的第一个键值就由53变为了49。同时,由于n1中的键值个数已经超过了阶数M,所以要对这个节点执行分裂操作。

图4.5 插入数据49及B+树的分裂

B+树节点分裂操作:

  • 创建兄弟节点brother,将分裂节点中后半部分键值挪动到brother中。
  • 并将brother中首个键值插入到父亲节点中,将brother节点设为父节点的孩子节点。

⑤ 插入145

直接将145插入到节点n2中去,因为插入后键值数量未超过B树的阶数,不需要分裂。

图4.6 向B+树中插入145

⑥ 插入36

将36插入到n1的首个位置处,然后更新器父亲节点对应的键值。(B+树中向叶子节点的首个关键字位置插入数据,一定会更新父亲节点的索引

图4.7 向B+树中插入36

⑦ 插入101

将101插入到n2的键值75和39之间,然后n2分裂。

图4.8 向B+树中插入101

4.2 B*树

相比于B+树,B*树要求每个分支节点的键值利用率达到\frac{2}{3}M,并且每一层节点又要存储指向其兄弟节点的指针,B*树相对于B+树,最大的优化就是节省了空间,能减少空间浪费。

图4.9 B*树的结构

五. B树索引原理

5.1 索引概述

索引,就是通过某些关键信息,让用户可以快速找到某些事物,例如通过目录,我们就可以快速检索到一本书中特定的内容所在的页码。B/B+最普遍的用途,就是做索引

MySQL数据库官方给出的索引定义是:索引(index)是帮助MySQL高效获取数据的数据结构。

当数据量很大的时候,为了方便数据的管理、提高检索效率,通常会将数据保存至数据库。数据库不仅仅要存储数据,还要维护特定的数据结构和一些高效的搜索算法,以帮助用户快速引用到某些数据。这种实现快速查找的数据结构,就是索引。

MySQL是非常流行的开源关系型数据库,不仅免费,而且搜索效率较高,可靠性高,拥有灵活的插件式存储引擎,在MySQL中,索引是属于存储引擎范畴的概念,不同的存储引擎对索引的实现方式是不同的。索引是基于表的而不是基于数据库的。

5.2 MyISAM

在早期的MySQL数据库中,所使用的搜索引擎都是MyISAM,这种搜索引擎不支持事务,支持全文索引,其使用的数据结构是B+树。在MyISAM搜索引擎中,叶子节点中的data域存储的是数据在磁盘中的地址,而不是数据本身。如图5.1所示的学生信息管理数据库,要记录学生的学号(StuId)、年龄(age)以及姓名,B+树用于检索,图5.1中选取的主键为StuId。

在绝大部分数据库中,一般要求加入到数据库中的数据要有一个主键,并且主键是不允许出现重复的。就以图5.1所示的学生信息管理系统为例,选取学号能保证每个学生之间的学号不重复,而姓名和年龄则不可避免的出现重复,那么就应当选取学号作为主键。如果没有一个合适的参数作为主键,那么可以采用自增主键,自增主键实际就是一个常数,第一次插入的数据常数1为主键,第二次插入的数据常数2为主键,以此类推。

图5.1 MyISAM主键索引

以图如果用户通过主键索引查找数据库中的相关信息,那么就会对B树进行检索,直到检索到叶子节点发现匹配项或者确认数据库中没有对应主键即可。如果使用非主键(未建立辅助索引)的参数进行检索,那么进行的操作是全表扫描查找匹配项

对于MySQL数据库,我们处理使用主键建立主索引之外,还可以建立辅助索引,主索引不允许出现重复项,而辅助索引允许出现重复项,如图5.2所示,就是通过学生年龄age建立的学生数据库的辅助索引。

图5.2 已age为主键的MyISAM辅助索引

5.3 InnoDB

现在高版本的MySQL数据库,全部采用InnoDB为搜索引擎,InnoDB是面向在线事务处理的应用,支持B+树索引、哈希索引、全文索引等。但是,InnoDB使用B+树支持索引的实现方式与MyISAM却有着很大的不同。

InnoDB文件本身就是索引文件的一部分。在InnoDB的中,B+树的叶子节点要存放表的全部数据,数据库中的数据,要按照主键从小到大的顺序排列起来。如图5.3所示,InnoDB的叶子节点中要包含所有的数据记录,这种索引叫做聚集索引。由于InnoDB数据文件本身要按照主键来聚集,因此InnoDB必须有主键,而MyISAM则可以没有主键

图5.3 InnoDB主键索引

InnoDB建立B+树辅助索引,叶子节点的数据域中记录的并不是数据数据文件本身的内容,而是对应的主键,如图5.4所示,在InnoDB索引方式下,建立对于name的辅助索引,叶子结点数据域就存储了对应的StdId(学号),使用辅助索引检索时,先拿到对应的主键,再通过主索引查找内容,这样就相当于要检索两次

图5.4 InnoDB辅助索引

六. 总结

  • 常见的搜索结构有哈希、二分、顺序查找、平衡二叉树等,这些数据结构和算法都只适用于内查找。
  • 对于海量数据,内存中无法容纳,应当使用B树/B+树来进行检索,B/B+树是高效的外查找专用数据结构。
  • MySQL数据库的检索主要是通过B+树来进行的,有MyISAM和InnoDB两种检索方式,MyISAM的B+树的叶子节点的数据域中存储的是数据文件在磁盘中的地址,InnoDB的B+树的叶子节点中数据域存放的是数据文件本身。
  • B+树做外查找时,B+树本身存储在磁盘中。

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

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

相关文章

使用条件格式突出显示单元格数据-sdk

使用条件格式突出显示单元格数据 2023 年 12 月 6 日 根据数据值将视觉提示应用于特定单元格、行或列&#xff0c;从而更轻松地识别模式和趋势。 网格中的条件格式允许用户根据单元格或范围包含的数据将视觉样式应用于单元格或范围。它通过以数据驱动的方式突出显示关键值、异常…

【3】密评-物理和环境安全测评

0x01 依据 GB/T 39786 -2021《信息安全技术 信息系统密码应用基本要求》针对等保三级系统要求&#xff1a; 物理和环境层面&#xff1a; a&#xff09;宜采用密码技术进行物理访问身份鉴别,保证重要区域进入人员身份的真实性&#xff1b; b&#xff09;宜采用密码技术保证电子门…

【面试经典150 | 二叉树】从中序与后序遍历序列构造二叉树

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;递归 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容…

VS2009和VS2022的错误列表可复制粘贴为表格

在VS2019或VS2022中&#xff0c;可看到如下错误列表&#xff1a; 如果复制这两行错误信息&#xff1a; 然后把它粘贴到word文件&#xff0c;就可以看到以下表格&#xff1a; 严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E0020 未定义标识符 "dd"…

【Redis】Redis 的学习教程(十三)Redis 各场景

由于Redis 支持比较丰富的数据结构&#xff0c;因此他能实现的功能并不仅限于缓存&#xff0c;而是可以运用到各种业务场景中&#xff0c;开发出既简洁、又高效的系统 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-bo…

【WPF.NET开发】WPF中的对话框

目录 1、消息框 2、通用对话框 3、自定义对话框 实现对话框 4、打开对话框的 UI 元素 4.1 菜单项 4.2 按钮 5、返回结果 5.1 模式对话框 5.2 处理响应 5.3 非模式对话框 Windows Presentation Foundation (WPF) 为你提供了自行设计对话框的方法。 对话框是窗口&…

每日一题:LeetCode-209. 长度最小的子数组(滑动窗口)

每日一题系列&#xff08;day 11&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

圆通速递查询,圆通速递单号查询,用表格导出查询好的物流信息

批量查询圆通速递单号的物流信息&#xff0c;以表格的形式导出查询好的物流信息。 所需工具&#xff1a; 一个【快递批量查询高手】软件 圆通速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主界…

同源策略与跨域

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 不论个人练习还是实际开…

千锋 Vue 详细笔记整理

视频笔记是根据B站 千锋 涛哥 - SpringBootvue前后端分离项目《锋迷商城》实战课-完结版 进行整理的 笔记可上 gitee仓库 自取 千锋 Vue 笔记整理 一、vue 的简介1.1 使用 JQuery 的复杂性问题1.2 VUE 简介1.2.1 前端框架1.2.2 MVVM 二、 vue 入门使用2.1 vue 的引入2.2 入门案…

期末速成数据库极简版【存储过程】(5)

目录 【7】系统存储过程 【8】用户存储过程——带输出参数的存储过程 创建存储过程 存储过程调用 【9】用户存储过程——不带输出参数的存储过程 【7】系统存储过程 系统存储我们就不做过程讲解用户存储过程会考察一道大题&#xff0c;所以我们把重点放在用户存储过程。…

Navicat 与 华为云 GaussDB 合作再升级,赋能 GaussDB 分布式数据库

2023 年第三季度&#xff0c;Navicat 首次支持了华为云 GaussDB 主备版数据库。经过双方团队进一步的深化合作&#xff0c;Navicat 完成了 GaussDB 分布式的研发适配工作&#xff0c;赋能 GaussDB 全域数据库产品。 GaussDB 数据库分为主备版和分布式版两种模式。主备版适用于…

【Backbone】TransNeXt:最新ViT模型(原理+常用神经网络汇总)

文章目录 一、近几年神经网络 Backbone 回顾1.Densenet 与 Resnet2.CBP3.SENet4.GCNet5.DANet6.PANet 与 FPN7.ASPP8.SPP-net9.PSP-net10.ECA-Net 二、TransNeXt&#xff08;2023&#xff09;1.提出问题2.Aggregated Pixel-focused Attention2.1 Pixel-focused Attention&#…

matlab RGB三元组和十六进制的转换

matlab画柱状图改颜色的时候&#xff0c;用三元组的形式&#xff0c;范围是[0&#xff0c;1] 我们获得了十六进制 到网站转换为[0,255] https://c.runoob.com/front-end/55/ 然后将得到的值/255 输入matlab就可以了

idea__SpringBoot微服务05——JSR303校验(新注解)(新的依赖),配置文件优先级,多环境切换

JSR303校验&#xff0c;配置文件优先级&#xff0c;多环境切换 一、JSR303数据校验二、配置文件优先级三、多环境切换一、properties多环境切换二、yaml多环境切换————————创作不易&#xff0c;如觉不错&#xff0c;随手点赞&#xff0c;关注&#xff0c;收藏(*&#x…

DOS命令

1.cd.. 返回主目录 2.cd 目录 切换到当前目录 3.dir 查看目录的所有文件夹 4.cls 清除dos窗口所有内容 5.键盘的向上箭头 查看上面输入的命令 6.exit退出dos窗口

国产化软件突围!怿星科技eStation产品荣获2023铃轩奖“前瞻优秀奖”

11月11日&#xff0c;2023中国汽车供应链峰会暨第八届铃轩奖颁奖典礼在江苏省昆山市举行。怿星科技凭借eStation产品&#xff0c;荣获2023铃轩奖“前瞻智能座舱类优秀奖”&#xff0c;怿星CEO潘凯受邀出席铃轩奖晚会并代表领奖。 2023铃轩奖“前瞻智能座舱类优秀奖” 铃轩奖&a…

JAVA实现敏感词高亮或打码过滤:sensitive-word

练手项目中实现发表文章时检测文章是否带有敏感词&#xff0c;以及对所有敏感词的一键过滤功能 文章目录 效果预览实现步骤 效果预览 随便复制一篇内容到输入框 机器审核文章存在敏感词&#xff0c;弹消息提示并进入人工审核阶段&#xff08;若机器审核通过&#xff0c;则无需审…

树莓派 5 - Raspberry Pi 5 入门教程

系列文章目录 文章目录 ​​​​​​​ 前言 如果您是第一次使用 Raspberry Pi&#xff0c;请参阅我们的入门指南&#xff08;how to get started&#xff09;。 Raspberry Pi 5 Raspberry Pi 5 配备了运行频率为 2.4GHz 的 64 位四核 Arm Cortex-A76 处理器&#xff0c;CPU 性…

【Selenium+Webmagic】基于JAVA语言实现爬取js渲染后的页面,附有代码

事先声明 笔者最近需要查看一些数据&#xff0c;自己挨个找太麻烦了&#xff0c;于是简单的学了一下爬虫。笔者在这里声明&#xff0c;爬的数据只为学术用&#xff0c;没有其他用途&#xff0c;希望来这篇文章学习的同学能抱有同样的目的。 枪本身不坏&#xff0c;坏的是使用枪…