C++进阶:AVL树详解及模拟实现(图示讲解旋转过程)

C++进阶:AVL树详解及模拟实现(图示讲解旋转过程)

之前在搜索二叉树最后早就埋下伏笔,来介绍AVL树和红黑树,今天就先来第一个吧


文章目录

  • 1.AVL树介绍
    • 1.1概念介绍
    • 1.2核心性质
  • 2.项目文件规划
  • 3.整体框架(节点和Tree)
  • 4.AVL树的新节点插入
    • 4.1新节点插入当前节点的右子树的右子树——左旋转
      • 左旋 (Left Rotation)
        • 情况:
        • 操作:
    • 4.2新节点插入当前节点的左子树的左子树——右旋转
      • 右旋 (Right Rotation)
        • 情况:
        • 操作:
    • 4.3新节点插入当前节点的左子树的右子树——左右双旋
      • 左右双旋(LR旋转)
    • 4.4新节点插入当前节点的右子树的左子树——右左双旋
      • 右左旋(RL旋转)
    • 4.5组装完整版Insert()
  • 5.中序方便过会测试
  • 6.编写函数看是否满足要求
    • 6.1求高度
    • 6.2 平衡否
  • 7.测试
  • 8.全部代码
    • 8.1 AVLTree.h
    • 8.2 test.cpp


1.AVL树介绍

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法,人为规定:

当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度

1.1概念介绍

  1. AVL树定义
    • 解释AVL树是一种自平衡的二叉搜索树,由G.M. Adelson-Velsky和E.M. Landis在1962年提出。
    • 强调AVL树中每个节点的平衡因子(Balance Factor),即左子树高度和右子树高度之差不超过1。
  2. 平衡因子
    • 解释平衡因子的概念,即一个节点的左子树高度减去右子树高度的值。
    • 平衡因子为{-1, 0, 1}时,树是平衡的。
  3. 自平衡性质
    • 说明AVL树具有自平衡性质,即在插入或删除节点时,会通过旋转操作来保持树的平衡。
    • 提及AVL树的平衡因子限制,确保树的高度保持在对数级别。

AVL1

1.2核心性质

  1. 严格平衡

    • 强调AVL树的严格平衡性质,即每个节点的左右子树高度差不超过1。
    • 严格平衡性质保证了AVL树的高度近似于对数级别,保证了高效的插入、删除和查找操作。
  2. 插入和删除操作

    • 介绍当插入或删除节点时,AVL树如何通过旋转操作来保持平衡。
    • 解释插入和删除操作可能会导致树失去平衡,需要通过单旋转、双旋转等操作进行调整。
  3. 时间复杂度

    • 说明AVL树的插入、删除和查找操作的时间复杂度都是O(log n),其中n为树中节点的数量。
    • 强调AVL树在动态数据集合中的高效性,适用于需要频繁更新的场景。

2.项目文件规划

在这里插入图片描述

头文件AVLTree.h:进行模拟的编写

源文件test.cpp:进行测试,检查代码逻辑是否满足期望

3.整体框架(节点和Tree)

template<class K,class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;//父亲节点int _bf; // balance factor 平衡因子pair<K, V> _kv;//每个节点里存一个pairAVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0), _kv(kv)//都直接在初始化列表里初始化了{}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;//名字太长了,叫Node也更好理解
public:private:Node* _root = nullptr;//给上缺省值
};

4.AVL树的新节点插入

基本步骤:

  1. 查找插入位置: 首先,我们需要找到新节点应该插入的位置。从根节点开始,按照二叉搜索树的性质,逐级向左或向右比较键值,直到找到一个合适的位置
  2. 插入新节点: 找到插入位置后,我们创建一个新的节点,并将其插入到树中。如果树为空,则新节点成为树的根节点。否则,将新节点插入到合适的位置,使得树仍然保持二叉搜索树的性质。
  3. 更新平衡因子: 在插入新节点后,需要沿着插入路径更新所有受影响节点的平衡因子。平衡因子是指节点的左右子树的高度差。如果插入导致某个节点的平衡因子超出范围(通常是 -1、0、1),则需要进行旋转操作来恢复平衡。
  4. 平衡调整: 如果插入操作破坏了 AVL 树的平衡性,我们需要进行一系列的旋转操作来重新平衡树。旋转操作包括单旋转和双旋转,具体的旋转方式取决于插入节点的位置以及平衡因子的情况。
  5. 旋转后继续向上: 插入节点后,可能需要对父节点、祖父节点等进行旋转操作,直到树恢复平衡为止。
	bool Insert(const pair<K, V>& kv){if (_root == nullptr)//如果是空树{_root = new Node(kv);return true;//插入成功}Node* cur = _root;Node* parent = nullptr;while (cur)//这里开始找位置{if (kv.first < cur->_kv.first)//小于往左走{parent = cur;cur = cur->_left;}else if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else{return false;//不能有相等的}}//开始把新节点链接上cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//更新平衡因子while (parent != nullptr)//cur到跟节点停下{if (cur == parent->_left)//在左就--{parent->_bf--;}else//在右++{parent->_bf++;}//开始检查父亲节点的情况if (parent->_bf == 0){break;//直接停止}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = cur->_parent;//向上走}else if (parent->_bf == 2 || parent->_bf == -2){//破坏了规则了,开始旋转}else{// 会到这说明插入之前AVL树就有问题assert(false);}}}

更新平衡因子过程:

更新的原则如下:

  • 如果新节点插入到父节点的左侧,则父节点的平衡因子减一。
  • 如果新节点插入到父节点的右侧,则父节点的平衡因子加一。

更新后,需要检查父节点的平衡因子是否发生变化,如果发生变化,则继续向上检查祖先节点的平衡因子,直到根节点或者到达一个平衡因子为 ±1 的节点为止。根据更新后节点的平衡因子情况,可以采取以下处理措施:

  • 如果节点的平衡因子为 0,表示节点所在子树的高度没有变化,不会影响祖先节点的平衡因子,更新结束
  • 如果节点的平衡因子为 ±1,表示节点所在子树的高度变化(本来是0,现在变成 ±1,子树高度变了),会影响祖先节点的平衡因子,需要继续向上更新祖先节点的平衡因子
  • 如果节点的平衡因子为 ±2,表示节点所在子树违反了平衡规则,需要进行平衡调整操作(如旋转),然后更新结束。

4.1新节点插入当前节点的右子树的右子树——左旋转

左旋 (Left Rotation)

左旋的情况是当一个节点的右子树过高,需要进行左旋来降低右子树的高度,同时保持树的平衡。

情况:
  1. 新节点插入到当前节点的右子树的右子树中,导致当前节点的平衡因子为 +2。
  2. 在双旋的过程中,当左子树的平衡因子为 -1,右子树的平衡因子为 +1。
操作:

左旋是指将当前节点向左旋转,使得当前节点的右子树的左子树成为当前节点的右子树,同时将当前节点成为其右子树的左子树。

    A                     B/ \                   / \T1  B       ==>       A   T3/ \               / \T2  T3            T1  T2

AVL2

	void RotateL(Node* parent){Node* subR = parent->_right;//要成为根的Node* subRL = subR->_left;//要成为30的右子树parent->_right = subRL;if (subRL != nullptr)subRL->_parent = parent;subR->_left = parent;Node* pparent = parent->_parent;//存一下,新根才能链接parent->_parent = subR;if (parent == _root){_root = subR;subR->_parent = nullptr;}else{if (ppnode->_left == parent)//parent在pp的左,那我新的跟subR也要左{ppnode->_left = subR;}else//同理{ppnode->_right = subR;}subR->_parent = ppnode;}//更新平衡因子parent->_bf = 0;subR->_bf = 0;}

4.2新节点插入当前节点的左子树的左子树——右旋转

右旋 (Right Rotation)

右旋的情况是当一个节点的左子树过高,需要进行右旋来降低左子树的高度,同时保持树的平衡。

情况:
  1. 新节点插入到当前节点的左子树的左子树中,导致当前节点的平衡因子为 -2。
  2. 在双旋的过程中,当左子树的平衡因子为 -1,右子树的平衡因子为 +1。
操作:

右旋是指将当前节点向右旋转,使得当前节点的左子树的右子树成为当前节点的左子树,同时将当前节点成为其左子树的右子树。

    A                     B/ \                   / \B   T3       ==>     T1   A/ \                       / \
T1  T2                    T2  T3

在这里插入图片描述

void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;Node* ppnode = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;subL->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = subL;}else{ppnode->_right = subL;}subL->_parent = ppnode;}subL->_bf = 0;parent->_bf = 0;}

4.3新节点插入当前节点的左子树的右子树——左右双旋

当新节点插入当前节点的左子树的右子树时,会触发左右双旋操作(LR旋转)。这种情况发生在当前节点的左子树的右子树上插入了新节点,导致当前节点的平衡因子不平衡(可能为+2或-2),且当前节点的左子树的右子树的平衡因子为正值(+1)。为了恢复 AVL 树的平衡性,需要先对当前节点的左子树进行一次左旋操作,然后再对当前节点进行一次右旋操作。

左右双旋(LR旋转)

具体步骤如下:

  1. 对当前节点的左子树进行一次左旋操作。
  2. 对当前节点进行一次右旋操作。

示例:

假设当前节点为 A,新节点插入在 A 的左子树的右子树的情况下,左右双旋操作如下:

        A                        A                        C/ \                      / \                      / \B   T4    左旋后         C   T4    右旋后         B   A/ \      --------->     / \       --------->    / \ / \T1   C                   B   T3                  T1 T2 T3 T4/ \                 / \T2  T3              T1  T2
void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;//存一下,后面要更新bfRotateL(parent->_left);RotateR(parent);if (bf == -1){subLR->_bf = 0;subL->_bf = 0;parent->_bf = 1;}else if (bf == 1){subLR->_bf = 0;subL->_bf = -1;parent->_bf = 0;}else if (bf == 0){subLR->_bf = 0;subL->_bf = 0;parent->_bf = 0;}else{assert(false);}}

4.4新节点插入当前节点的右子树的左子树——右左双旋

右左旋(RL旋转)

右左旋操作发生在节点的右子树过深,导致平衡因子为 -2 且其右子节点的平衡因子为 +1 的情况下。具体步骤如下:

  1. 对 A 的右子树进行一次左旋操作。
  2. 再对 A 进行一次右旋操作。

示例:

    A                     A                    C/ \                   / \                  / \T1  B       ==>      T1   C      ==>       A   B/ \                   / \              / \ / \C   T4                T2  B            T1 T2 T3 T4/ \                       / \T2  T3                    T3  T4
void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;}else{parent->_bf = 0;subR->_bf = 0;}}

4.5组装完整版Insert()

bool Insert(const pair<K, V>& kv){if (_root == nullptr)//如果是空树{_root = new Node(kv);return true;//插入成功}Node* cur = _root;Node* parent = nullptr;while (cur)//这里开始找位置{if (kv.first < cur->_kv.first)//小于往左走{parent = cur;cur = cur->_left;}else if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else{return false;//不能有相等的}}//开始把新节点链接上cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//更新平衡因子while (parent != nullptr)//cur到跟节点停下{if (cur == parent->_left)//在左就--{parent->_bf--;}else//在右++{parent->_bf++;}//开始检查父亲节点的情况if (parent->_bf == 0){break;//直接停止}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = cur->_parent;//向上走}else if (parent->_bf == 2 || parent->_bf == -2){//破坏了规则了,开始旋转if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}else{RotateRL(parent);}break;//调整完后就平衡了,也不用向上,直接出去}else{// 会到这说明插入之前AVL树就有问题assert(false);}}}

5.中序方便过会测试

	void InOrder(){_InOrder(_root);}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << "[" << root->_bf << "]" << endl;_InOrder(root->_right);}

6.编写函数看是否满足要求

只要有一个节点的左子树与右子树的高度差距大于等于2,那么就不满足了

从这里也能看出要写一个求高度函数更方便

6.1求高度

	int Height(){_Height(_root);}int _Height(Node* root){if (root == nullptr){return 0;}int right = _Height(root->_right);int left = _Height(root->_left);return right > left ? right + 1 : left + 1;}

这段代码实现了 AVL 树的高度计算和平衡性检查功能。

_Height 函数:

这个函数用于计算给定树的高度。递归地计算左右子树的高度,然后返回较大的子树高度加上 1。这个函数被用于计算整棵树的高度。

Height 函数:

这个函数是对外提供的接口,用于获取 AVL 树的高度。它调用 _Height 函数并传入根节点,返回整棵 AVL 树的高度。

6.2 平衡否

	bool IsBalance(){int height = 0;return _IsBlance(_root, height);}bool _IsBlance(Node* root, int& h){if (root == nullptr){h = 0;return true;}int leftHeight = 0, rightHeight = 0;if (!_IsBlance(root->_left, leftHeight)|| !_IsBlance(root->_right, rightHeight)){return false;}if (abs(rightHeight - leftHeight) >= 2){cout << root->_kv.first << "不平衡" << endl;return false;}h= leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;return true;}

_IsBalance 函数:

这个函数用于检查 AVL 树的平衡性。它递归地检查树的每个节点,计算左右子树的高度并比较它们的差值,如果差值大于等于 2,则表示不平衡。此外,还检查每个节点的平衡因子是否正确,即右子树高度减去左子树高度等于节点的平衡因子。如果平衡因子异常,则表示树不平衡。

IsBalance 函数:

这个函数是对外提供的接口,用于检查整棵 AVL 树的平衡性。它调用 _IsBalance 函数并传入根节点,返回整棵 AVL 树是否平衡的结果。

这些函数的实现是 AVL 树的重要部分,用于确保 AVL 树保持平衡性和正确性。


7.测试

void TestAVLTree1()
{int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };AVLTree<int, int> t;for (auto e : a){t.Insert(make_pair(e, e));cout << e << "->" << t.IsBalance() << endl;}t.InOrder();cout << t.IsBalance() << endl;
}

在这里插入图片描述


8.全部代码

8.1 AVLTree.h

#pragma oncetemplate<class K,class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;//父亲节点int _bf; // balance factor 平衡因子pair<K, V> _kv;//每个节点里存一个pairAVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0), _kv(kv)//都直接在初始化列表里初始化了{}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;//名字太长了,叫Node也更好理解
public:void RotateL(Node* parent){Node* subR = parent->_right;//要成为根的Node* subRL = subR->_left;//要成为30的右子树parent->_right = subRL;if (subRL != nullptr)subRL->_parent = parent;subR->_left = parent;Node* ppnode = parent->_parent;//存一下,新根才能链接parent->_parent = subR;if (parent == _root){_root = subR;subR->_parent = nullptr;}else{if (ppnode->_left == parent)//parent在pp的左,那我新的跟subR也要左{ppnode->_left = subR;}else//同理{ppnode->_right = subR;}subR->_parent = ppnode;}//更新平衡因子parent->_bf = 0;subR->_bf = 0;}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;Node* ppnode = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;subL->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = subL;}else{ppnode->_right = subL;}subL->_parent = ppnode;}subL->_bf = 0;parent->_bf = 0;}void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;//存一下,后面要更新bfRotateL(parent->_left);RotateR(parent);if (bf == -1){subLR->_bf = 0;subL->_bf = 0;parent->_bf = 1;}else if (bf == 1){subLR->_bf = 0;subL->_bf = -1;parent->_bf = 0;}else if (bf == 0){subLR->_bf = 0;subL->_bf = 0;parent->_bf = 0;}else{assert(false);}}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;}else{parent->_bf = 0;subR->_bf = 0;}}bool Insert(const pair<K, V>& kv){if (_root == nullptr)//如果是空树{_root = new Node(kv);return true;//插入成功}Node* cur = _root;Node* parent = nullptr;while (cur)//这里开始找位置{if (kv.first < cur->_kv.first)//小于往左走{parent = cur;cur = cur->_left;}else if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else{return false;//不能有相等的}}//开始把新节点链接上cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//更新平衡因子while (parent != nullptr)//cur到跟节点停下{if (cur == parent->_left)//在左就--{parent->_bf--;}else//在右++{parent->_bf++;}//开始检查父亲节点的情况if (parent->_bf == 0){break;//直接停止}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = cur->_parent;//向上走}else if (parent->_bf == 2 || parent->_bf == -2){//破坏了规则了,开始旋转if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}else{RotateRL(parent);}break;//调整完后就平衡了,也不用向上,直接出去}else{// 会到这说明插入之前AVL树就有问题assert(false);}}}void InOrder(){_InOrder(_root);}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << "[" << root->_bf << "]" << endl;_InOrder(root->_right);}int Height(){_Height(_root);}int _Height(Node* root){if (root == nullptr){return 0;}int right = _Height(root->_right);int left = _Height(root->_left);return right > left ? right + 1 : left + 1;}bool IsBalance(){int height = 0;return _IsBlance(_root, height);}bool _IsBlance(Node* root, int& h){if (root == nullptr){h = 0;return true;}int leftHeight = 0, rightHeight = 0;if (!_IsBlance(root->_left, leftHeight)|| !_IsBlance(root->_right, rightHeight)){return false;}if (abs(rightHeight - leftHeight) >= 2){cout << root->_kv.first << "不平衡" << endl;return false;}h= leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;return true;}private:Node* _root = nullptr;//给上缺省值
};void TestAVLTree1()
{int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };AVLTree<int, int> t;for (auto e : a){t.Insert(make_pair(e, e));cout << e << "->" << t.IsBalance() << endl;}t.InOrder();cout << t.IsBalance() << endl;
}

8.2 test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<assert.h>#include"AVLTree.h"
int main()
{TestAVLTree1();return 0;
}

今天就到这里啦!!下一次肯定是红黑树啦!!!

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

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

相关文章

JDK 1.8 HashMap扩容机制

我们首先来看利用无参构造函数创建HashMap如何扩容。首先创建一个无参构造出来的hashmap HashMap hashMap new HashMap();该构造函数源码如下&#xff1a; public HashMap() {this.loadFactor DEFAULT_LOAD_FACTOR; // all other fields defaulted}此时&#xff0c;该构造函…

linux笔记5--shell命令2

文章目录 一. linux中的任务管理1. 图形界面2. 命令① top命令② grep命令③ ps命令补充&#xff1a; ④ kill命令图形界面杀死进程 二. 挂载(硬盘方面最重要的一个知识点)1. 什么是挂载2. 关于挂载目录① Windows② linux查看硬件分区情况(/dev下)&#xff1a;更改挂载目录结束…

揭秘 HTTP 代理:增强在线活动的安全性和匿名性

HTTP 代理在保护您的在线隐私、增强安全性以及允许访问受限内容方面发挥着关键作用。了解 HTTP 代理的工作原理以及如何有效地利用它们可以让您掌控自己的在线状态和浏览体验。让我们深入研究 HTTP 代理的世界&#xff0c;探索它们的优势、应用程序以及最大化其效用的最佳实践。…

【Unity Shader入门精要 第6章】基础光照(二)

1. 获取环境光 unity shader中可以通过 UNITY_LIGHTMODEL_AMBIENT获取当前环境光颜色信息。 fixed4 frag(v2f i) : SV_Target {return UNITY_LIGHTMODEL_AMBIENT; }2. 漫反射 2.1 兰伯特模型 创建Chapter_6_Diffuse_Lambert作为测试材质创建Chapter_6_Diffuse_Lambert作为测…

ollama api只能局域网访问,该怎么破?

安装ollama: ollama离线安装,在CPU运行它所支持的那些量化的模型-CSDN博客文章浏览阅读178次,点赞2次,收藏6次。ollama离线安装,在CPU运行它所支持的哪些量化的模型 总共需要修改两个点,第一:Ollama下载地址;第二:Ollama安装包存放目录。第二处修改,修改ollama安装目…

洛谷官方提单——【入门4】数组——python

洛谷官方提单——【入门4】数组 小鱼比可爱题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示代码 小鱼的数字游戏题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示数据规模与约定 代码 【深基5.例3】冰雹猜想题目描述输入格式输出格式样例 #1样例输入 …

matlab打开文件对话框

在使用matlab GUI制作时&#xff0c;为了便于用户交互使用&#xff0c;经常设置文件打开对话框&#xff0c;让用户根据实际需要选择打开的文件。下面以打开一张图片为例&#xff0c;matlab代码如下&#xff1a; [temp_filepath,temp_filename]uigetfile(*.jpg,请选择要打开的图…

从心理学角度看,GPT 对人有什么影响?

开启个性化AI体验&#xff1a;深入了解GPT的无限可能 导言 GPT 与我们日常生活的融合标志着技术进步的重大飞跃&#xff0c;为提高效率和创新提供了前所未有的机遇。然而&#xff0c;当我们与这些智能系统日益紧密地交织在一起时&#xff0c;探索它们对个人产生的细微的心理影响…

电子杂志制作攻略,轻松打造高质量数字出版物

随着数字科技的飞速发展&#xff0c;电子杂志作为一种新型的数字出版物&#xff0c;已经越来越受到人们的青睐。它不仅具有丰富的内容、多样的形式&#xff0c;还具有便捷的传播和阅读方式。如今&#xff0c;电子杂志已经逐渐成为企业、媒体和个人展示自身品牌、传播信息的重要…

下载驱动包提示 通常不会下载 未验证的下载

打开设置 添加允许站点 如果还是下载不了&#xff0c;那只能换资源了

发那科数控机床远程监控数据上云

发那科数控机床远程监控数据上云 在当今数字化、网络化的工业生产环境中&#xff0c;发那科数控机床作为全球领先的高端制造设备之一&#xff0c;其远程监控数据上云已成为实现智能制造、提升生产效率和优化资源管理的重要手段。本文将深入探讨发那科数控机床远程监控数据上云…

ACE框架学习4

目录 ACE Proactor框架 异步I/O工厂类 ACE_Handler类 前摄式Acceptor-Connector类 ACE_Proactor类 ACE Streams框架 ACE_Model类 ACE_Streams类 ACE Proactor框架 ACE Proactor框架实现了proactor模式&#xff0c;也就是异步网络模式&#xff0c;允许事件驱动…

axios异步操作第一篇

1 同步请求和异步请求 客户端给java后台程序发送请求&#xff0c;发送请求的方式有两种&#xff1a; 同步请求 同步请求发送方式&#xff1a; 1 浏览器地址栏&#xff0c;输入url&#xff1a;http://localhost:8080/web-app/xxxServlet 2 3 删除 4 javascript:location.hr…

运营商的mpls专线

在当今高速发展的数字化时代&#xff0c;网络已成为企业发展不可或缺的基础设施。作为企业网络 连接的重要组成部分&#xff0c;MPLS专线在运营商的推动下逐渐成为了企业选择的首选。 MPLS&#xff08;Multi-Protocol Label Switching&#xff09;是一种基于标签的交换技术&am…

探索渲染农场的高性能奥秘

在当今数字化的时代&#xff0c;渲染农场正逐渐成为许多行业不可或缺的强大工具。那么&#xff0c;为什么我们说渲染农场是高性能的计算机系统呢&#xff1f;让我们深入剖析其中关键要点。 “渲染农场”拥有大规模的计算资源。它由众多高性能的计算机节点组成&#xff0c;这些…

理解伽马分布

伽马分布 关键词&#xff1a;Gamma Distribution 文章目录 一、说明二、Gamma 分布的基础概念2.1 Gamma 分布的物理意义2.2 对比泊松与伽马分布2.3 伽马分布参数 三、具有伽马分布的高效牙科调度四、后记 一、说明 在本文中&#xff0c;我们将探讨统计学中的基本概率分布之一…

【C++】命名空间、缺省参数、函数重载、引用

文章目录 1.认识命名空间2.命名空间的使用3.C的输入和输出4.缺省参数4.1缺省参数的概念4.2缺省参数的分类 5.函数重载6.引用6.1引用的概念6.2引用的特性6.3常引用(重点题目)6.4引用和指针的区别 1.认识命名空间 C总计63个关键字&#xff0c;C语言32个关键字 下面让我们学习一…

周进院长受邀出席2024第四届屈光手术国际论坛获多项荣誉称号!

周进院长受邀出席2024第四届屈光手术国际论坛获“全国首批EVOICL&#xff08;V5&#xff09;新技术临床应用专家”等多项荣誉称号&#xff01; 5月10-12日&#xff0c;由爱尔眼科医院集团主办、长沙爱尔眼科医院协办的2024第四届屈光手术国际论坛&#xff08;IRSS 2024&#x…

618洗地机怎么选?热门洗地机选购指南,拒绝踩雷

洗地机是一种智能化的清洁工具&#xff0c;具有超强的清洁能力&#xff0c;能轻松应对各种地面污渍&#xff0c;无论是干污还是湿污。其一键操作设计简便易上手&#xff0c;省去了传统清洁方式的繁琐步骤&#xff0c;节省了时间和精力。高端型号更配备智能感应功能&#xff0c;…

ARP中间人

文章目录 ARP中间人ARP协议介绍使用kali进行ARP毒化使用kali进行ARP中间人使用kali进行ARP钓鱼ARP攻击防御ARP总结 ARP中间人 ARP协议介绍 维基百科ARP介绍 ARP&#xff08;地址解析协议&#xff09;在网络通信中扮演着至关重要的角色&#xff0c;它通过将网络层地址&#x…