【数据结构】—搜索二叉树(C++实现,超详细!)

                                                      🎬慕斯主页修仙—别有洞天

                                                       ♈️今日夜电波:消えてしまいそうです—真夜中

                                                                1:15━━━━━━️💟──────── 4:18
                                                                    🔄   ◀️   ⏸   ▶️    ☰  

                                      💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍


目录

一、二叉搜索树概念

        什么是二叉搜索树? 

        二叉搜索树的基本操作

二、二叉搜索树的实现

         节点的定义

         二叉搜索树的定义

非递归操作

        插入操作

        查找操作 

        删除操作(重点及难点!!!)

递归法操作 

        中序遍历排升序(经典操作!) 

         插入操作(递归)

         查找操作(递归)

        删除操作(递归) 

 二叉搜索树的应用

        KV模型二叉搜索树

三、整体代码 


一、二叉搜索树概念

        什么是二叉搜索树? 

二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树,它满足以下几个条件:

  1. 左子树中所有节点的值小于当前节点的值。
  2. 右子树中所有节点的值大于当前节点的值。
  3. 左子树和右子树也都是二叉搜索树。

        二叉搜索树的中序遍历可以得到一个升序的序列,因此它常被用来实现有序集合或映射。在二叉搜索树中,查找、插入和删除操作的时间复杂度通常为O(logn),其中n为树中节点的数量,这得益于二叉搜索树的结构和查找方法。

         如下便是一颗二叉搜索树:

        一句话总结二叉搜索树:

                左子树节点总是比父节点小,右子树节点总是比父节点大的二叉树。

        二叉搜索树的基本操作

         利用二叉搜索树特性排升序。一听到二叉树,我们通常会想到的是什么?递归!请细细想想我们二叉搜索树的特点->左边的节点总是比父节点小,右边的节点总是比父节点大!那么我们对它使用中序遍历会发生什么呢?还是上面的那颗二叉树,对他进行中序遍历后:

        中序遍历结果:arr={1,3,4,6,7,8,10,13,14};

二、二叉搜索树的实现

         节点的定义

          说来惭愧作者在此前实现数据结构都是用C语言实现的 o (╥﹏╥)o. ,本文应该是作为作者第一篇用C++实现的数据结构,也算是一个新的起点吧!

        与C语言的区别主要还是在于在此使用struct(实际上是类)可以在定义时就进行初始化,利用的就是类的初始化列表的作用,这就省去了我们C语言时需要额外定义以及调用的初始化操作。只能说有了C++,C语言什么的不认识啦ʅ(´◔౪◔)ʃ

	//节点定义template<class K>struct BSTreeNode{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}};

         二叉搜索树的定义

         对于节点实例化并且重命名,并且给数据进行缺省赋值。

	//二叉搜索树template<class K>class BSTree{typedef BSTreeNode<K> Node;public://...诸多的操作private:Node* _root = nullptr;};

非递归操作

        插入操作

        插入的具体过程如下:

        a. 树为空,则直接新增节点,赋值给root指针

        b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

         思路:判断是否为空->是-》直接给根节点赋值->否->进行循环遍历对要插入的值进行“比大小”->大往右,小往左遍历,直到空为止->比较空位置父节点的大小,大插右,小插左

		//插入操作,按照左小右大的规则bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;}}cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}

        查找操作 

        通过搜索二叉树的特性,通过比较大小即可完成查找。

		//查找操作bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return true;}}return false;}

        删除操作(重点及难点!!!)

         首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:

        a. 要删除的结点无孩子结点

        b. 要删除的结点只有左孩子结点

        c. 要删除的结点只有右孩子结点

        d. 要删除的结点有左、右孩子结点

        看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:

        情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除

        情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除

        情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除

        而在b、c、d这三种情况中,b和c又很相似,所以以大类来划分,我们实际可以分为两种。一种是要删除的节点只有一个左孩子或者右孩子,另一种是有两个孩子节点。

         现在详细介绍这两种情况:

        当只有一个孩子节点时: 当要删节点的左孩子为空时,我们只需要将右半边给他的父亲就行,当然我们也需要注意以下两点:1、如果要删节点是根节点,那么我们需要将它的右孩子的地址覆盖原节点。2、要删节点不是根节点,那么我们也需要判断要删节点是它父节点的左孩子还是右孩子;左孩子则父节点的左孩子节点指向要删孩子的右孩子,右孩子则父节点的右孩子节点指向要删孩子的右孩子。当要删右孩子时也是同理,只是需要注意此时要注意的第二点中要指向的是要删节点是右孩子。下面上半部分的图为此部分的图解~

          当有两个孩子节点时:我们则需要用到替换法。首先,我们需要根据以下规则中的一个规则:1、找到要删节点的左子树的最大节点。2、找到要删奇点的右子树的最小节点。接着,交换要删节点和找到的这个节点。最后,删除找到节点的位置,这个时候,我们就需要返回到上一部分我们只有一个孩子节点时要走的步骤,进行相应的操作为什么呢?因为我们都知道要找最小或者最大只有在最左或者最右。而此时我们一定满足只有一个孩子节点时的于要求。下面下半部分的图为此部分的图解,这里取右子树的最小~

        实现如下: 

		bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else//表示已经找到,进行删除操作{//左为空的情况if (cur->_left == nullptr){if (cur == _root)//要删即为根节点{_root = cur->_right;}else{if (cur == parent->_left)//因为左一定为空,为父节点的左则将右半边给父即可{parent->_left = cur->_right;}else//同理为父节点的右则将右半边给父{parent->_right = cur->_right;}}delete cur;}else if (cur->_right == nullptr)//右为空的情况{//同理左为空if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}else//左右都不为空{//可以选择找该节点左子树的最大节点(最右节点)或者右子树的最小节点(最左节点)//这里找右树的最小节点(最左节点)Node* parent = cur;Node* subleft = cur->_right;while (subleft->_left){parent = subleft;subleft = subleft->_left;}swap(cur->_key, subleft->_key);//由于找到的是最左,则默认左为空,所以只需将右链接给父节点if (subleft == parent->_left){parent->_left = subleft->_right;}else{parent->_right = subleft->_right;}delete subleft;}return true;}}return false;}

        

递归法操作 

        中序遍历排升序(经典操作!) 

        上面详细介绍过了,不多阐述~

		void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}

         插入操作(递归)

        实际上同非递归的原理是相同的,不多阐述。实在不行画递归展开图就理解了~

		bool _InsertR(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key < key)return _InsertR(root->_right, key);else if (root->_key > key)return _InsertR(root->_left, key);elsereturn false;}

         查找操作(递归)

		bool _FindR(Node* root, const K& key){if (root == nullptr){return false;}if (root->_key < key){return _FindR(root->_right, key);}else if (root->_key > key){return _FindR(root->_left, key);}else{return true;}}

        删除操作(递归) 

        实际上操作同非递归是一致的 ,特别注意接口的对于root的引用,这对于后续删除很有作用。当要删除只有一个孩子节点的节点时,同非递归的思想是一样的。当要删节点有两个孩子节点时,在最后面采取的是装换成在子树中去删除,同非递归中的找到替换节点转到只有一个孩子的操作是一样的思想。

		bool _EraseR(Node*& root, const K& key){if (root == nullptr)return false;if (root->_key < key){return _EraseR(root->_right, key);}else if (root->_key > key){return _EraseR(root->_left, key);}else//找到了开始删除{//实际上的操作同非递归差不多,这里巧妙的对root运用了引用if (root->_left == nullptr){Node* del = root;root = root->_right;delete del;return true;}else if (root->_right == nullptr){Node* del = root;root = root->_left;delete del;return true;}else//找右子树的最大{Node* subleft = root->_right;while (subleft->_left){subleft = subleft->_left;}swap(root->_key, subleft->_key);// 转换成在子树去递归删除return _EraseR(root->_right, key);}}}

 二叉搜索树的应用

        以上我们实现的二叉搜索树实际上也被称为K模型,而实际上还有一种模型叫做KV模型,以下为详细介绍:
         1. K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。比如:

        给一个单词word,判断该单词是否拼写正确,具体方式如下:

        以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树

        在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

        2. KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见:比如

        英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;

        再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对

        KV模型二叉搜索树

        KV模型实际上同K模型差不多, 只是在K模型的基础上加了一个value值,对于其它的操作都是相似的,以下给出KV模型的整体代码:

namespace kv
{template<class K, class V>struct BSTreeNode{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _value;BSTreeNode(const K& key, const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){}};template<class K, class V>class BSTree{typedef BSTreeNode<K, V> Node;public:bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;}}cur = new Node(key, value);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return cur;}}return nullptr;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{// 准备删除  20:15继续if (cur->_left == nullptr){//左为空if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr){//右为空if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else{//左右都不为空// 右树的最小节点(最左节点)Node* parent = cur;Node* subLeft = cur->_right;while (subLeft->_left){parent = subLeft;subLeft = subLeft->_left;}swap(cur->_key, subLeft->_key);if (subLeft == parent->_left)parent->_left = subLeft->_right;elseparent->_right = subLeft->_right;}return true;}}return false;}void InOrder(){_InOrder(_root);cout << endl;}private:void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}private:Node* _root = nullptr;};}

三、整体代码 

#pragma once
#include<iostream>
using namespace std;namespace K
{//节点定义template<class K>struct BSTreeNode{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}};//二叉搜索树template<class K>class BSTree{typedef BSTreeNode<K> Node;public://插入操作,按照左小右大的规则bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;}}cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}//查找操作bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return true;}}return false;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else//表示已经找到,进行删除操作{//左为空的情况if (cur->_left == nullptr){if (cur == _root)//要删即为根节点{_root = cur->_right;}else{if (cur == parent->_left)//因为左一定为空,为父节点的左子树则将右半边给父即可{parent->_left = cur->_right;}else//同理为父节点的右则将右半边给父{parent->_right = cur->_right;}}delete cur;}else if (cur->_right == nullptr)//右为空的情况{//同理左为空if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}else//左右都不为空{//可以选择找该节点左子树的最大节点(最右节点)或者右子树的最小节点(最左节点)//这里找右树的最小节点(最左节点)Node* parent = cur;Node* subleft = cur->_right;while (subleft->_left){parent = subleft;subleft = subleft->_left;}swap(cur->_key, subleft->_key);//由于找到的是最左,则默认左为空,所以只需将右链接给父节点if (subleft == parent->_left){parent->_left = subleft->_right;}else{parent->_right = subleft->_right;}delete subleft;}return true;}}return false;}void InOrder()//中序遍历即排升序{_InOrder(_root);cout << endl;}bool FindR(const K& key)//递归找{return _FindR(_root, key);}bool InsertR(const K& key)//递归插入{return _InsertR(_root, key);}bool EraseR(const K& key)//递归删{return _EraseR(_root, key);}BSTree() = default;// C++11~BSTree(){Destroy(_root);}BSTree(const BSTree<K>& t){_root = Copy(t._root);}// t1 = t3BSTree<K>& operator=(BSTree<K> t){swap(_root, t._root);return *this;}private:Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* newRoot = new Node(root->_key);newRoot->_left = Copy(root->_left);newRoot->_right = Copy(root->_right);return newRoot;}void Destroy(Node*& root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;root = nullptr;}bool _EraseR(Node*& root, const K& key){if (root == nullptr)return false;if (root->_key < key){return _EraseR(root->_right, key);}else if (root->_key > key){return _EraseR(root->_left, key);}else//找到了开始删除{//实际上的操作同非递归差不多,这里巧妙的对root运用了引用if (root->_left == nullptr){Node* del = root;root = root->_right;delete del;return true;}else if (root->_right == nullptr){Node* del = root;root = root->_left;delete del;return true;}else//找右子树的最大{Node* subleft = root->_right;while (subleft->_left){subleft = subleft->_left;}swap(root->_key, subleft->_key);// 转换成在子树去递归删除return _EraseR(root->_right, key);}}}bool _InsertR(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key < key)return _InsertR(root->_right, key);else if (root->_key > key)return _InsertR(root->_left, key);elsereturn false;}bool _FindR(Node* root, const K& key){if (root == nullptr){return false;}if (root->_key < key){return _FindR(root->_right, key);}else if (root->_key > key){return _FindR(root->_left, key);}else{return true;}}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}Node* _root = nullptr;};
}namespace kv
{template<class K, class V>struct BSTreeNode{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _value;BSTreeNode(const K& key, const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){}};template<class K, class V>class BSTree{typedef BSTreeNode<K, V> Node;public:bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;}}cur = new Node(key, value);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return cur;}}return nullptr;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{// 准备删除  20:15继续if (cur->_left == nullptr){//左为空if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr){//右为空if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else{//左右都不为空// 右树的最小节点(最左节点)Node* parent = cur;Node* subLeft = cur->_right;while (subLeft->_left){parent = subLeft;subLeft = subLeft->_left;}swap(cur->_key, subLeft->_key);if (subLeft == parent->_left)parent->_left = subLeft->_right;elseparent->_right = subLeft->_right;}return true;}}return false;}void InOrder(){_InOrder(_root);cout << endl;}private:void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}private:Node* _root = nullptr;};}

                        感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

                                       

                                                                         给个三连再走嘛~  

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

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

相关文章

函数计算的新征程:使用 Laf 构建 AI 知识库

Laf 已成功上架 Sealos 模板市场&#xff0c;可通过 Laf 应用模板来一键部署&#xff01; 这意味着 Laf 在私有化部署上的扩展性得到了极大的提升。 Sealos 作为一个功能强大的云操作系统&#xff0c;能够秒级创建多种高可用数据库&#xff0c;如 MySQL、PostgreSQL、MongoDB …

js实现获取原生form表单的数据序列化表单以及将数组转化为一个对象obj,将数组中的内容作为对象的key转化为对象,对应的值转换为对象对应的值

1.需求场景 哈喽 大家好啊&#xff0c;今天遇到一个场景&#xff0c; js实现获取原生form表单的数据序列化表单以及将数组转化为一个对象obj&#xff0c;将数组中的内容作为对象的key转化为对象&#xff0c;对应的值转换为对象对应的值 数组对象中某个属性的值&#xff0c;转…

元宇宙现已开放!

在 2023 年 11 月 3 日 The Sandbox 首个全球创作者日上&#xff0c;The Sandbox 联合创始人 Arthur Madrid 和 Sebastien Borget 宣布元宇宙已开放&#xff0c;已创作完整体验的 LAND 持有者可以自行将体验发布至 The Sandbox 地图上。 精选速览 LAND 持有者&#xff1a;如果…

在JVM中 判定哪些对象是垃圾?

目录 垃圾的条件 1、引用计数法 2、可达性分析 3、强引用 4、软引用 5、弱引用 6、虚引用 判断垃圾的条件 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;垃圾收集器负责管理内存&#xff0c;其中的垃圾收集算法用于确定哪些对象是垃圾&#xff0c;可以被回收…

VBA即用型代码手册之工作薄的关闭保存及创建

我给VBA下的定义&#xff1a;VBA是个人小型自动化处理的有效工具。可以大大提高自己的劳动效率&#xff0c;而且可以提高数据的准确性。我这里专注VBA,将我多年的经验汇集在VBA系列九套教程中。 作为我的学员要利用我的积木编程思想&#xff0c;积木编程最重要的是积木如何搭建…

[Latex] Riemann 问题中的激波,接触间断,膨胀波的 Tikz 绘图

Latex 代码 \begin{figure}\begin{subfigure}[b]{0.32\textwidth}\centering\resizebox{\linewidth}{!}{\begin{tikzpicture}\coordinate (o) at (0,0);\coordinate (Si) at (2.5,2.5);\coordinate (x) at (1,0);\draw[->] (0,0) -- (3,0) node[right] {$x$};\draw[->] …

ArkTS-自定义组件学习

文章目录 创建自定义组件页面和自定义组件生命周期自定义组件和页面的区别页面生命周期(即被Entry修饰的组件)组件生命周期(即被Component修饰的组件) Builder装饰器&#xff1a;自定义构建函数按引用传递参数按值传递参数 BuilderParam装饰器&#xff1a;引用Builder函数 这个…

生物动力葡萄酒和有机葡萄酒一样吗?

农业维持了数十万年的文明&#xff0c;但当人类以错误的方式过多干预&#xff0c;过于专注于制造和操纵产品时&#xff0c;农业往往会失败。如果我们的目标是获得最高质量的收成&#xff0c;并长期坚持我们的做法&#xff0c;我们就必须与土地打交道。 当我们开始寻找生物动力…

应用内测分发平台如何上传应用包体?

●您可免费将您的应用&#xff08;支持苹果.ios安卓.apk文件&#xff09;上传至咕噜分发平台&#xff0c;我们将免费为应用生成下载信息&#xff0c;但咕噜分发将会对应用的下载次数进行收费&#xff08;每个账号都享有免费赠送的下载点数以及参加活动的赠送点数&#xff09;&a…

【电路笔记】-分压器

分压器 文章目录 分压器1、概述2、负载分压器3、分压器网络4、无功分压器4.1 电容分压器4.2 感应分压器 5、总结 有时&#xff0c;需要精确的电压值作为参考&#xff0c;或者仅在需要较少功率的电路的特定阶段之前需要。 分压器是解决此问题的一个简单方法&#xff0c;因为它们…

【Vue】filter的用法

上一篇&#xff1a; vue的指令 https://blog.csdn.net/m0_67930426/article/details/134599378?spm1001.2014.3001.5502 本篇所使用指令 v-for v-on v-html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"&…

记一次docker服务启动失败解决过程

环境&#xff1a;centos 7.6 报错&#xff1a;start request repeated too quickly for docker.service 由于服务器修复了内核漏洞&#xff0c;需要重启&#xff0c;没想到重启后&#xff0c;docker启动失败了 查看状态 systemctl status docker如下图 里面有一行提示&…

网络互联与IP地址

目录 网络互联概述网络的定义与分类网络的定义网络的分类 OSI模型和DoD模型网络拓扑结构总线型拓扑结构星型拓扑结构环型拓扑结构 传输介质同轴电缆双绞线光纤 介质访问控制方式CSMA/CD令牌 网络设备网卡集线器交换机路由器总结 IP地址A、B、C类IP地址特殊地址形式 子网与子网掩…

DCDC电感发热啸叫原因分析

一、电感发热啸叫原因解析 发热原因&#xff1a;电感饱和&#xff0c;实际使用的电感值<理论电感计算值 原因1&#xff1a;电感选择过小&#xff0c;计算值不合理。 原因2&#xff1a;PCB布局不合理&#xff0c;屏蔽型电感下方应设禁止铺铜区。 啸叫原因&#xff1a; 人耳的…

Log4j2.xml不生效:WARN StatusLogger Multiple logging implementations found:

背景 将 -Dlog4j.debug 添加到IDEA的类的启动配置中 运行上图代码&#xff0c;这里log4j2.xml控制的日志级别是info&#xff0c;很明显是没生效。 DEBUG StatusLogger org.slf4j.helpers.Log4jLoggerFactory is not on classpath. Good! DEBUG StatusLogger Using Shutdow…

Camera Raw v16.0.0(PS Raw增效工具)

Camera Raw 16是一款允许摄影师处理原始图像文件的软件PS增效工具。原始图像文件是未经相机内部软件处理的数码照片&#xff0c;因此包含相机传感器捕获的所有信息。Camera Raw 为摄影师提供了一种在将原始文件转换为更广泛兼容的格式&#xff08;如 JPEG 或 TIFF&#xff09;之…

搭建SRS视频服务器

去官方网站下载FFmpeg6.1 https://ffmpeg.org/download.html拷贝到CentOS7.9中的/opt目录下&#xff0c;解压并重命名 tar -xvf ffmpeg-6.1.tar.xz 解压后编译安装 ./configure make make install从github下载SRS4.0release 解压后 如果ffmpeg的路径不在/usr/local/bin/ffmpe…

【MATLAB】全网入门快、免费获取、持续更新的科研绘图教程系列2

14 【MATLAB】科研绘图第十四期表示散点分布的双柱状双Y轴统计图 %% 表示散点分布的双柱状双Y轴统计图%% Made by Lwcah &#xff08;公众号&#xff1a;Lwcah&#xff09; %% 公众号&#xff1a;Lwcah %% 知乎、B站、小红书、抖音同名账号:Lwcah&#xff0c;感谢关注~ %% 更多…

LeetCode二叉树小题目

Q1将有序数组转换为二叉搜索树 题目大致意思就是从一个数组建立平衡的二叉搜索树。由于数组以及进行了升序处理&#xff0c;我们只要考虑好怎么做到平衡的。平衡意味着左右子树的高度差不能大于1。由此我们可以想着是否能用类似二分递归来解决。 如果left>right,直接返回nul…

IO多路转接之epoll

目录 一. epoll的实现原理 二. epoll的相关接口 2.1 epoll_create -- 创建epoll模型 2.2 epoll_ctl -- 对epoll模型进行控制 2.3 epoll_wait -- 等待epoll所关注的事件就绪 2.4 epoll相关接口的使用方法 三. Epoll服务器的模拟实现 3.1 EpollServer类的声明 3.2 Epoll…