实现AVL树

目录

AVL树概念

AVL树结构

AVL树插入

LL型 - 右单旋

RR型 - 左单旋

LR型 - 左右双旋

RL型 - 右左双旋

插入代码实现

AVL树测试

 附AVL树实现完整代码


AVL树概念

前面的博客介绍了搜索二叉树,二叉搜索树-CSDN博客

在某些特定的情况下,⼆叉搜索树是会退化成单链表的,并且各种操作的效率也会明显的下降,因此我们需要⼀些特别的⼿段保证这个⼆叉搜索树的“平衡”,进⽽保证各种操作的 效率。这就是我们接下来要学习的平衡⼆叉树

为了保证⼆叉搜索树的性能,规定在插⼊和删除结点时,要保证任意结点的左、⼦树⾼度差的绝对值不超过1 ,这样的⼆叉树称为平衡⼆叉树(简称AVL树)。

其中结点左⼦树与右⼦树的⾼度差定义为该结点的平衡因⼦(⼀般是左⼦树的⾼度减去右⼦树的⾼ 度。当然,反过来也是可以的)

由此可⻅,平衡⼆叉树中,每⼀个结点的平衡因⼦只可能是 0/1/-1,如下图所⽰:结点上⽅的数字表⽰平衡因⼦。左图是⼀棵平衡⼆叉树,右图不是⼀棵平衡⼆叉树

AVL树结构

我们采用三叉链的结构实现节点,因为AVL树调平衡的过程需要向上找父节点,因此需要存储父节点的指针信息

template<class K, class V>
struct AVLTreeNode
{//三叉链AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _bf; //平衡因子AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
private:Node* _root = nullptr;
};

AVL树插入

在⼆叉搜索树中插⼊新结点之后,插⼊路径的点中,可能存在很多平衡因⼦的绝对值⼤于1的,此时找到距离插⼊结点最近的不平衡的点,以这个点为根的字树就是不平衡子树。如下图:

插⼊之后,会导致三个结点失衡,其中距离最近的 结点为根的⼦树,就是最小不平衡子树。可以发现,仅需让最⼩不平衡⼦树平衡,所有结点就都平衡了,感性认知如下:

1. 本来整棵树就是平衡⼆叉树,如果来了⼀个结点导致失衡,那么失衡结点的平衡因⼦只能是2或者 -2;

2 .当我们把最⼩平衡⼦树调整平衡之后,那么这棵⼦树的⾼度就会减 ,向上传递的过程中,会让 整个路径⾥⾯的平衡因⼦都向0靠近⼀位,原来的-2会变成-1,原来的2会变成1,整棵树就变得平衡了。

而最⼩不平衡⼦树的出现可以细分成4种情况,因此调整策略也会分为4种情况讨论。为了方便叙述, 设最小不平衡子树的根节点为T。

LL型 - 右单旋

 LL 表示:新结点由于插⼊在T结点的左孩⼦(L)的左⼦树(LL)中,从⽽导致失衡。如下图所示:

此时需要将L右旋:

• 将结点L向右上旋转代替结点T作为根结点;

• 将节点T向右下旋转作为结点L的右⼦树的根结点;

• 结点L的原右⼦树(LR)则作为结点T的左⼦树

旋转之后,依旧满⾜平衡⼆叉树的特性:LL < L < LR < T < R

案例:下列AVL树中插⼊1

最⼩不平衡⼦树是以 13 为根的⼦树,引起不平衡的原因是 13的左孩⼦的左⼦树上插⼊⼀个新的结点,因此需要右旋⼀次。右旋的结点为10

代码实现:

void RotateR(Node *parent)
{Node *subL = parent->_left;Node *subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node *parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subL;}else{parentParent->_right = subL;}subL->_parent = parentParent;}subL->_bf = parent->_bf = 0;
}
RR型 - 左单旋

RR表⽰:新结点由于插⼊在T结点的右孩⼦(R)的右⼦树(RR)中,从⽽导致失衡。如下图所⽰:

此时需要⼀次向左的旋转操作,将R左旋:

• 将结点R向左上旋转代替结点T作为根结点;

• 将节点T向左下旋转作为结点R的左⼦树的根结点;

• 结点R的原左⼦树(RL)则作为结点T的右⼦树。 如下图:

案例:下列AVL树中插⼊64

最⼩不平衡⼦树是以 49 为根的⼦树,引起不平衡的原因是 49 的右孩⼦的右⼦树上插⼊⼀个新的结 点,因此需要左旋⼀次。左旋的结点为59

代码实现

void RotateL(Node *parent)
{Node *subR = parent->_right;Node *subRL = subR->_left;parent->_right = subRL;subR->_left = parent;// 旋转之后整棵子树的根变了, 需要重新链接Node *parentParent = parent->_parent;parent->_parent = subR;if (subRL)subRL->_parent = parent;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}parent->_bf = subR->_bf = 0;
}
LR型 - 左右双旋

LR表⽰:新结点由于插⼊在T结点的左孩⼦(L)的右⼦树(LR)中,从⽽导致失衡。如下图所⽰:

此时需要两次旋转操作,先将LR左旋,再将LR右旋。

将LR左旋:

• 将结点LR向左上旋转代替结点L作为根结点;

• 将节点L向左下旋转作为结点LR的左⼦树的根结点;

• 结点LR的原左⼦树(LRL)则作为结点L的右⼦树。

将LR右旋:

• 将结点LR向右上旋转代替结点T作为根结点;

• 将节点T向右下旋转作为结点LR的右⼦树的根结点;

• 结点LR的原右⼦树(LRR)则作为结点T的左⼦树。

案例:下列AVL树中插⼊1

最⼩不平衡⼦树是以49为根的⼦树,引起不平衡的原因是49的左孩⼦的右⼦树上插⼊⼀个新的结点,因此需要左旋⼀次,然后右旋⼀次。旋转的结点为45:

void RotateLR(Node *parent)
{Node *subL = parent->_left;Node *subLR = subL->_right;int bf = subLR->_bf; // subLR不可能为nullptr,因为subL的平衡因子是-1RotateL(subL);RotateR(parent);// 3、更新平衡因子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 = subL->_bf = parent->_bf = 0;}else{assert(false); // 在旋转前树的平衡因子就有问题}
}
RL型 - 右左双旋

RL表⽰:新结点由于插⼊在T结点的右孩⼦(R)的左⼦树(RL)中,从⽽导致失衡。如下图所⽰:

此时需要两次旋转操作,先将RL右旋,再将RL左旋。将RL右旋:

• 将结点RL向右上旋转代替结点R作为根结点;

• 将节点R向右下旋转作为结点RL的右⼦树的根结点;

• 结点RL的原右⼦树(RLR)则作为结点R的右⼦树。

将RL左旋:

• 将结点RL向左上旋转代替结点T作为根结点;

• 将节点T向左下旋转作为结点RL的左⼦树的根结点;

• 结点RL的原左⼦树(RLL)则作为结点T的右⼦树。

案例:下列AVL树中插⼊52

最⼩不平衡⼦树是以49为根的⼦树,引起不平衡的原因是49的右孩⼦的左⼦树上插⼊⼀个新的结点,因此需要右旋⼀次,然后再左旋⼀次。旋转的结点为55

代码实现

void RotateRL(Node *parent)
{Node *subR = parent->_right;Node *subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 0){parent->_bf = subR->_bf = subRL->_bf = 0;}else if (bf == -1){parent->_bf = 1;subRL->_bf = 0;subR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subRL->_bf = 0;subR->_bf = -1;}else{assert(false);}
}
插入代码实现
bool Insert(const pair<K, V> &kv)
{if (_root == nullptr){_root = new Node(kv);return true;}Node *parent = nullptr;Node *cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}while (parent){// 平衡因子的变化if (cur == parent->_left){parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 0) // 之前为-1/1, cur填到了较低的一边,树高不变,不需要继续调整了!{break;}else if (parent->_bf == 1 || parent->_bf == -1) // 之前为0, 当前树高+1, 可能不再平衡了,向上调整!{cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2) // 失衡了, 需要重新调平衡{if (parent->_bf == 2 && cur->_bf == 1){RotateR(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateL(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateLR(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateRL(parent);}// 1、旋转让这颗子树平衡了// 2、旋转降低了这颗子树的高度,恢复到跟插入前一样的高度,所以对上一层没有影响,不用继续更新break;}else{assert(false);}}return true;
}

● 首先和二叉搜索树一样,先找到合适的插入位置,再进行插入

● 插入后更新当前子树的平衡因子,然后根据平衡因子的特点执行不同的操作

● 如果当前子树的平衡因子是0,说明依旧平衡,不需要调平衡;如果当前子树的平衡因子是1/-1,需要继续向上找最小不平衡子树;如果当前子树的平衡因子是2/-2,说明找到了最小不平衡子树,根据平衡因子的特点,执行不同的旋转操作,只要最小不平衡子树调平衡了,整棵树就平衡了,直接跳出循环即可

AVL树测试

判断是否是平衡二叉树:

public:bool IsBalance(){return _IsBalance(_root);}private:bool _IsBalance(Node* root){if (root == nullptr)return true;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);if (leftHeight - rightHeight != root->_bf){cout << root->_kv.first << "平衡因子异常" << endl;return false;}return abs(leftHeight - rightHeight) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}int _Height(Node* root){if (root == nullptr)return 0;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}

中序遍历

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

main函数测试

#include <iostream>
#include <assert.h>
using namespace std;#include "AVL.h"void test1()
{int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };AVLTree<int, int> t;for (auto e : a){t.Insert(make_pair(e, e));}t.InOrder();cout << t.IsBalance() << endl;
}void test2()
{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));}t.InOrder();cout << t.IsBalance() << endl;
}#include <vector>
void test3()
{const int N = 30;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; i++){v.push_back(rand());cout << v.back() << endl;}AVLTree<int, int> t;for (auto e : v){t.Insert(make_pair(e, e));cout << "Insert:" << e << "->" << t.IsBalance() << endl;}cout << t.IsBalance() << endl;
}int main()
{test1();test2();test3();return 0;
}

 附AVL树实现完整代码

#pragma once
#include<assert.h>
#include <iostream>
using namespace std;//AVL树:
//1.本质还是一颗二叉搜索树
//2.增加了平衡因子,任何一颗子树的左右子树高度差绝对值不超过1template<class K, class V>
struct AVLTreeNode
{//三叉链AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _bf; //平衡因子AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public:bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}while (parent) {//平衡因子的变化if (cur == parent->_left){parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 0) //之前为-1/1, cur填到了较低的一边,树高不变,不需要继续调整了!{break;}else if (parent->_bf == 1 || parent->_bf == -1) //之前为0, 当前树高+1, 可能不再平衡了,向上调整!{cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2)  //失衡了, 需要重新调平衡{if (parent->_bf == 2 && cur->_bf == 1) {RotateR(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateL(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateLR(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateRL(parent);}// 1、旋转让这颗子树平衡了// 2、旋转降低了这颗子树的高度,恢复到跟插入前一样的高度,所以对上一层没有影响,不用继续更新break;}else{assert(false);}}return true;}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;subR->_left = parent;//旋转之后整棵子树的根变了, 需要重新链接Node* parentParent = parent->_parent;parent->_parent = subR;if (subRL)subRL->_parent = parent;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}parent->_bf = subR->_bf = 0;}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subL;}else{parentParent->_right = subL;}subL->_parent = parentParent;}subL->_bf = parent->_bf = 0;}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);if(bf == 0){parent->_bf = subR->_bf = subRL->_bf = 0;}else if (bf == -1){parent->_bf = 1;subRL->_bf = 0;subR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subRL->_bf = 0;subR->_bf = -1;}else{assert(false);}}//左右双旋void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf; //subLR不可能为nullptr,因为subL的平衡因子是-1RotateL(subL);RotateR(parent);//3、更新平衡因子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 = subL->_bf = parent->_bf = 0;}else{assert(false); //在旋转前树的平衡因子就有问题}}void InOrder(){_InOrder(_root);cout << endl;}bool IsBalance(){return _IsBalance(_root);}private:bool _IsBalance(Node* root){if (root == nullptr)return true;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);if (leftHeight - rightHeight != root->_bf){cout << root->_kv.first << "平衡因子异常" << endl;return false;}return abs(leftHeight - rightHeight) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}int _Height(Node* root){if (root == nullptr)return 0;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);}
private:Node* _root = nullptr;
};

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

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

相关文章

unity学习11:地图相关的一些基础

目录 1 需要从 unity的 Asset Store 下载资源 1.1 下载资源 1.2 然后可以从 package Manager 里选择下载好的包&#xff0c;import到项目里 2 创建地形 2.1 创建地形 2.2 地形 Terrain大小 2.3 各种网格的尺寸大小 2.4 比较这个地形尺寸和创建的其他物体的大小对比 3 …

【vue】晋升路线图、蛇形进度条

一、效果图&#xff08;参考链接&#xff09; 代码实现 <template><div class"only-content"><h1 class"text-center my-3">讲师晋升路线</h1><!--时间轴线显示--><div class"time-line"><div class&qu…

VisionPro软件Image Stitch拼接算法

2D图像拼接的3种情景 1.一只相机取像位置固定&#xff0c;或者多只相机固定位置拍图&#xff0c;硬拷贝拼图&#xff0c;采用CopyRegion工具实现 2.一只或多只相机在多个位置拍照&#xff0c;相机视野互相重叠&#xff0c;基于Patmax特征定位后&#xff0c;无缝 拼图&#xff…

vue2项目报错You may need an appropriate loader to handle this file type

npm run 运行 vue2 项目时报错如下&#xff1a; error in ./node_modules/quill/formats/blockquote.jsModule parse failed: Unexpected token (3:18) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this …

Cyber Security 101-Web Hacking-Burp Suite: The Basics(Burp Suite:基础知识)

使用 Burp Suite 进行 Web 应用程序渗透测试的简介。 任务1&#xff1a;介绍 欢迎来到 Burp Suite Basics&#xff01; 这个特定的房间旨在了解 Burp Suite Web 应用程序安全测试框架的基础知识。我们的重点将围绕 以下关键方面&#xff1a; Burp Suite 的全面介绍。全面概述…

基于Informer网络实现电力负荷时序预测——cross validation交叉验证与Hyperopt超参数调优

前言 系列专栏:【深度学习&#xff1a;算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域&#xff0c;讨论了各种复杂的深度神经网络思想&#xff0c;如卷积神经网络、循环神经网络、生成对…

【计算机网络】课程 实验二 交换机基本配置和VLAN 间路由实现

实验二 交换机基本配置和VLAN 间路由实现 一、实验目的 1&#xff0e;了解交换机的管理方式。 2&#xff0e;掌握通过Console接口对交换机进行配置的方法。 3&#xff0e;掌握交换机命令行各种模式的区别&#xff0c;能够使用各种帮助信息以及命令进行基本的配置。 4&…

MySQL入门学习笔记

第一章 数据库系统概述 数据库的4个基本概念 数据、数据库、数据库管理系统、数据库系统是与数据库技术密切相关的4个基本概念 数据 数据是数据库中存储的基本对象&#xff0c;描述事物的符号记录称为数据&#xff0c;数据的表现形式还不能完全表达其内容&#xff0c;需要…

【C++】构造函数与析构函数

写在前面 构造函数与析构函数都是属于类的默认成员函数&#xff01; 默认成员函数是程序猿不显示声明定义&#xff0c;编译器会中生成。 构造函数和析构函数的知识需要建立在有初步类与对象的基础之上的&#xff0c;关于类与对象不才在前面笔记中有详细的介绍&#xff1a;点我…

海外云服务器能用来做什么?

海外云服务器不仅服务种类繁多&#xff0c;而且能满足多行业的需求&#xff0c;方便了越来越多的企业与个人。本文将探讨海外云服务器的核心服务及其适用领域&#xff0c;帮助企业更好地了解这一技术资源。 云存储&#xff1a;安全高效的数据管理 海外云服务器为用户提供了稳定…

计算机毕业设计Python+CNN卷积神经网络高考推荐系统 高考分数线预测 高考爬虫 协同过滤推荐算法 Vue.js Django Hadoop 大数据毕设

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

基于物联网的冻保鲜运输智能控制系统

基于物联网的冻保鲜运输智能控制系统设计文档 1. 项目开发背景 随着全球化贸易的发展&#xff0c;冷链物流在现代运输行业中扮演着日益重要的角色。尤其是冻品、食品、药品等对运输环境有着严格要求的货物&#xff0c;其运输过程中温度、湿度等环境参数必须严格控制&#xff…

资源分享:gpts、kaggle、paperswithcode

gpts 似乎是gpt agent集合&#xff0c;专注于不同细分方向的ai助手。 kaggle 专注于AI相关的培训、竞赛、数据集、大模型。 paperswithcode 简单直接&#xff0c;内容如同网站地址&#xff0c;直接提供优秀代码和配套的论文&#xff0c;似乎还有数据集。

谷歌浏览器的书签同步功能详解

谷歌浏览器作为全球最受欢迎的网络浏览器之一&#xff0c;提供了众多强大的功能来提升用户的上网体验。其中&#xff0c;书签同步功能允许用户在不同设备之间无缝地同步浏览器数据&#xff0c;如书签、历史记录、密码等。本文将详细解析谷歌浏览器的书签同步功能&#xff0c;教…

pip error: microsoft visual c++ 14.0 or greater is required

报错原因&#xff1a;软件包作者发布的是为编译的*.tar.gz包&#xff0c;我们安装的时候需要调用系统C编译器来进行编译安装&#xff0c;如果系统没有安装编译器或者编译器版本不对就会报这个错误。 解决方式一&#xff1a;安装编译器&#xff0c;但不需要安装完整的visual c …

Windows提示msvcp120.dll丢失怎么解决?Windows文件丢失的4种解决方法,教你修复msvcp120.dll文件

Windows提示msvcp120.dll丢失&#xff1f;别担心&#xff0c;这里有4种解决方法&#xff01; 作为软件开发领域的一名从业者&#xff0c;我经常遇到用户反馈关于Windows系统报错的问题&#xff0c;其中“msvcp120.dll丢失”是一个较为常见的错误。今天&#xff0c;我将为大家科…

ESP32-C3 AT WiFi AP 启 TCP Server 被动接收模式 + BLE 共存

TCP 被动接收模式&#xff0c;每次发的数据会先存到缓冲区&#xff0c;参见&#xff1a;ATCIPRECVTYPE 指令说明。 即每包数据不会实时报告 IPD 接收情况&#xff0c;如果需要查询缓冲区的数据&#xff0c;先用 ATCIPRECVLEN? 指令查询被动接收模式下套接字数据的长度 。获取…

51单片机——8*8LED点阵

LED 点阵的行则为发光二极管的阳极&#xff0c;LED 点阵的列则为发光二极管的阴极 根据 LED 发光二极管导通原理&#xff0c;当阳极为高电平&#xff0c;阴极为低电平则点亮&#xff0c;否则熄灭。 因此通过单片机P0口可控制点阵列&#xff0c;74HC595可控制点阵行 11 脚 SR…

pytest测试用例管理框架特点及常见语法和用法分享

一、pytest及其特点 1. 什么是pytest pytest 是一个功能强大且灵活的 Python 测试框架&#xff0c;也是目前最流行的测试框架&#xff0c;可以让我们很方便的编写和管理自动化测试用例&#xff0c;并提供丰富的插件来满足单元测试、集成测试、性能测试等各种测试需求。 2. p…