c++(AVL树及其实现)
一、AVL树的概念
AVL树是最先发明的自平衡⼆叉查找树,AVL是⼀颗空树,或者具备下列性质的⼆叉搜索树:它的
左右子树都是AV树,且左右子树的高度差的绝对值不超过1。AVL树是⼀颗高度平衡搜索⼆叉树,
通过控制高度差去控制平衡。
AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis是两个前苏联的科学家,他们在1962
年的论文《An algorithm for the organization of information》中发表了它。
AVL树实现这里我们引入⼀个平衡因子(balance factor)的概念,每个结点都有⼀个平衡因子,任何
结点的平衡因子等于右子树的高度减去左子树的高度,也就是说任何结点的平衡因子等于0/1/-1,
AVL树并不是必须要平衡因子,但是有了平衡因子可以更方便我们去进行观察和控制树是否平衡,
就像⼀个风向标⼀样。
思考⼀下为什么AVL树是高度平衡搜索⼆叉树,要求高度差不超过1,而不是高度差是0呢?0不是更
好的平衡吗?画画图分析我们发现,不是不想这样设计,而是有些情况是做不到高度差是0的。⽐
如⼀棵树是2个结点,4个结点等情况下,高度差最好就是1,无法作为高度差是0
AVL树整体结点数量和分布和完全⼆叉树类似,高度可以控制在 ,那么增删查改的效率也可
以控制在 ,相比⼆叉搜索树有了本质的提升。


二、AVL树的实现
1、AVL树的结构
#pragma once
#include<iostream>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{// 需要parent指针,后续更新平衡因子可以看到pair<K, V> _kv;AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf; // balance factorAVLTreeNode(const pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _bf(0){}
};
template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public:
private:Node * _root = nullptr;
};
2、插入
-
插入一个值按⼆叉搜索树规则进行插入。
-
新增结点以后,只会影响祖先结点的高度,也就是可能会影响部分祖先结点的平衡因子,所以更新
从新增结点->根结点路径上的平衡因子,实际中最坏情况下要更新到根,有些情况更新到中间就可
以停止了,具体情况我们下面再详细分析。
-
更新平衡因子过程中没有出现问题,则插入结束
-
更新平衡因子过程中出现不平衡,对不平衡子树旋转,旋转后本质调平衡的同时,本质降低了子树
的高度,不会再影响上⼀层,所以插入结束。
3、平衡因子更新
更新原则:
平衡因子 = 右子树高度-左子树高度
只有子树高度变化才会影响当前结点平衡因子。
插入结点,会增加高度,所以新增结点在parent的右子树,parent的平衡因子++,新增结点在
parent的左子树,parent平衡因子–
parent所在子树的高度是否变化决定了是否会继续往上更新
更新停止条件:
更新后parent的平衡因子等于0,更新中parent的平衡因子变化为-1->0 或者 1->0,说明更新前
parent子树⼀边高⼀边低,新增的结点插入在低的那边,插入后parent所在的子树高度不变,不会
影响parent的父亲结点的平衡因子,更新结束。
更新后parent的平衡因子等于1 或 -1,更新前更新中parent的平衡因子变化为0->1 或者 0->-1,说
明更新前parent子树两边⼀样高,新增的插入结点后,parent所在的子树⼀边高⼀边低,parent所
在的子树符合平衡要求,但是高度增加了1,会影响arent的父亲结点的平衡因子,所以要继续向上
更新。
更新后parent的平衡因子等于2 或 -2,更新前更新中parent的平衡因子变化为1->2 或者 -1->-2,说
明更新前parent子树⼀边高⼀边低,新增的插入结点在高的那边,parent所在的子树高的那边更高
了,破坏了平衡,parent所在的子树不符合平衡要求,需要旋转处理,旋转的⽬标有两个:1、把
parent子树旋转平衡。2、降低parent子树的高度,恢复到插入结点以前的高度。所以旋转后也不
需要继续往上更新,插入结束。
更新到10结点,平衡因子为2,10所在的子树已经不平衡,需要旋转处理

更新到中间结点,3为根的子树高度不变,不会影响上⼀层,更新结束

最坏更新到根停⽌

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->_left = cur;}else{parent->_right = cur;}//更新平衡因子while (parent){if (cur == parent->_left)parent->_bf--;elseparent->_bf++;if (parent->_bf == 0){break;}else if (parent->_bf == -1 || parent->_bf == 1){cur = parent;parent = parent->_parent;}else if (parent->_bf == -2 || parent->_bf == 2){//选转break;}}}
4、旋转
a、右单旋
本图1展⽰的是10为根的树,有a/b/c抽象为三棵高度为h的子树(h>=0),a/b/c均符合AVL树的要
求。10可能是整棵树的根,也可能是⼀个整棵树中局部的子树的根。这里a/b/c是高度为h的子树,
是⼀种概括抽象表示,他代表了所有右单旋的场景,实际右单旋形态有很多种,具体图2/图3/图4/
图5进行了详细描述。
在a子树中插入⼀个新结点,导致a子树的高度从h变成h+1,不断向上更新平衡因子,导致10的平
衡因子从-1变成-2,10为根的树左右高度差超过1,违反平衡规则。10为根的树左边太高了,需要
往右边旋转,控制两棵树的平衡。
旋转核心步骤,因为5 < b子树的值 < 10,将b变成10的左子树,10变成5的右子树,5变成这棵树新
的根,符合搜索树的规则,控制了平衡,同时这棵的高度恢复到了插入之前的h+2,符合旋转原
则。如果插入之前10整棵树的⼀个局部子树,旋转后不会再影响上⼀层,插入结束了。





代码:
void RotateR(Node* parent)
{Node* Pparent = parent->_parent;Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;// 需要注意除了要修改孩子指针指向,还是修改父亲if (subLR)//防止对空指针解引用 subLR->_parent = parent;subL->_right = parent;parent->_parent = subL;if (Pparent == nullptr)//parent是根时{_root = subL;subL->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subL;}else{parentParent->_right = subL;}subL->_parent = parentParent;}//更新平衡因子parent->_bf = subL->_bf = 0;
}
b、左单旋
本图6展示的是10为根的树,有a/b/c抽象为三棵高度为h的子树(h>=0),a/b/c均符合AVL树的要
求。10可能是整棵树的根,也可能是⼀个整棵树中局部的子树的根。这里a/b/c是高度为h的子树,
是⼀种概括抽象表示,他代表了所有右单旋的场景,实际右单旋形态有很多种,具体跟上⾯左旋类
似。
在a子树中插入⼀个新结点,导致a子树的高度从h变成h+1,不断向上更新平衡因子,导致10的平
衡因子从1变成2,10为根的树左右高度差超过1,违反平衡规则。10为根的树右边太高了,需要往
左边旋转,控制两棵树的平衡。
旋转核心步骤,因为10 < b子树的值 < 15,将b变成10的右子树,10变成15的左子树,15变成这棵
树新的根,符合搜索树的规则,控制了平衡,同时这棵的高度恢复到了插入之前的h+2,符合旋转
原则。如果插入之前10整棵树的⼀个局部子树,旋转后不会再影响上⼀层,插入结束了。

代码:
void RotateL(Node* parent)
{Node* Pparent = parent->_parent;Node* subR = parent->_right;Node* subRL = subL->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;subR->_left = parent;parent->_parent = subR;if (Pparent == nullptr)//parent是根时{_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}parent->_bf = subR->_bf = 0;
}
c、左右双旋
通过图7和图8可以看到,左边高时,如果插入位置不是在a子树,而是插入在b子树,b子树高度从h变
成h+1,引发旋转,右单旋无法解决问题,右单旋后,我们的树依旧不平衡。右单旋解决的纯粹的左边
高,但是插入在b子树中,10为跟的子树不再是单纯的左边高,对于10是左边高,但是对于5是右边
高,需要用两次旋转才能解决,以5为旋转点进行⼀个左单旋,以10为旋转点进行⼀个右单旋,这棵树
这棵树就平衡了


图7和图8分别为左右双旋中h=0和h=1具体场景分析,下面我们将a/b/c子树抽象为高度h的AVL
子树进行分析,另外我们需要把b子树的细节进⼀步展开为8和左子树高度为h-1的e和f子树,因为
我们要对b的父亲5为旋转点进行左单旋,左单旋需要动b树中的左子树。b子树中新增结点的位置
不同,平衡因子更新的细节也不同,通过观察8的平衡因子不同,这里我们要分三个场景讨论。
场景1:h >= 1时,新增结点插⼊在e子树,e子树高度从h-1变为h并不断更新8->5->10平衡因子,
引发旋转,其中8的平衡因子为-1,旋转后8和5平衡因子为0,10平衡因子为1。
场景2:h >= 1时,新增结点插⼊在f子树,f子树高度从h-1变为h并不断更新8->5->10平衡因子,引
发旋转,其中8的平衡因子为1,旋转后8和10平衡因子为0,5平衡因子为-1。
场景3:h == 0时,a/b/c都是空树,b⾃⼰就是⼀个新增结点,不断更新5->10平衡因子,引发旋
转,其中8的平衡因子为0,旋转后8和10和5平衡因子均为0。

void RotateLR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;//根据subLR的平衡因子判断RotateL(parent->_left);RotateR(parent);if (bf == 0){subL->_bf = 0;subLR->_bf = 0;parent->_bf = 0;}else if (bf == -1){subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1)parent->_bf = 1;{subL->_bf = -1;subLR->_bf = 0;parent->_bf = 0;}else{assert(false);}
}
d、右左双旋
跟左右双旋类似,下⾯我们将a/b/c子树抽象为⾼度h的AVL子树进⾏分析,另外我们需要把b子树的
细节进⼀步展开为12和左子树⾼度为h-1的e和f子树,因为我们要对b的⽗亲15为旋转点进⾏右单
旋,右单旋需要动b树中的右子树。b子树中新增结点的位置不同,平衡因子更新的细节也不同,通
过观察12的平衡因子不同,这⾥我们要分三个场景讨论。
场景1:h >= 1时,新增结点插⼊在e子树,e子树⾼度从h-1变为h并不断更新12->15->10平衡因
子,引发旋转,其中12的平衡因子为-1,旋转后10和12平衡因子为0,15平衡因子为1。
场景2:h >= 1时,新增结点插⼊在f子树,f子树⾼度从h-1变为h并不断更新12->15->10平衡因子,
引发旋转,其中12的平衡因子为1,旋转后15和12平衡因子为0,10平衡因子为-1。•
场景3:h == 0时,a/b/c都是空树,b自己就是⼀个新增结点,不断更新15->10平衡因子,引发旋
转,其中12的平衡因子为0,旋转后10和12和15平衡因子均为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){subR->_bf = 0;subRL->_bf = 0;parent->_bf = 0;}else if (bf == 1){subR->_bf = 0;subRL->_bf = 0;parent->_bf = -1;}else if (bf == -1){subR->_bf = 1;subRL->_bf = 0;parent->_bf = 0;}else{assert(false);}
}
三、整体代码
#pragma once
#include<iostream>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{// 需要parent指针,后续更新平衡因⼦可以看到pair<K, V> _kv;AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf; // balance factorAVLTreeNode(const pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _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;}else{parent->_left = cur;}// 链接父亲cur->_parent = parent;if (parent->_kv->first > kv.first){parent->_left = cur;}else{parent->_right = cur;}//更新平衡因子while (parent){if (cur == parent->_left)parent->_bf--;elseparent->_bf++;if (parent->_bf == 0){break;}else if (parent->_bf == -1 || parent->_bf == 1){cur = parent;parent = parent->_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;}}}void RotateR(Node* parent){Node* Pparent = parent->_parent;Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;// 需要注意除了要修改孩⼦指针指向,还是修改⽗亲if (subLR)//防止对空指针解引用 subLR->_parent = parent;subL->_right = parent;parent->_parent = subL;if (Pparent == nullptr)//parent是根时{_root = subL;subL->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subL;}else{parentParent->_right = subL;}subL->_parent = parentParent;}//更新平衡因子parent->_bf = subL->_bf = 0;}void RotateL(Node* parent){Node* Pparent = parent->_parent;Node* subR = parent->_right;Node* subRL = subL->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;subR->_left = parent;parent->_parent = subR;if (Pparent == nullptr)//parent是根时{_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}parent->_bf = subR->_bf = 0;}void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;//根据subLR的平衡因子判断RotateL(parent->_left);RotateR(parent);if (bf == 0){subL->_bf = 0;subLR->_bf = 0;parent->_bf = 0;}else if (bf == -1){subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1)parent->_bf = 1;{subL->_bf = -1;subLR->_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(parent->_right);RotateL(parent);if (bf == 0){subR->_bf = 0;subRL->_bf = 0;parent->_bf = 0;}else if (bf == 1){subR->_bf = 0;subRL->_bf = 0;parent->_bf = -1;}else if (bf == -1){subR->_bf = 1;subRL->_bf = 0;parent->_bf = 0;}else{assert(false);}}
private:Node * _root = nullptr;
};
相关文章:
c++(AVL树及其实现)
一、AVL树的概念 AVL树是最先发明的自平衡⼆叉查找树,AVL是⼀颗空树,或者具备下列性质的⼆叉搜索树:它的 左右子树都是AV树,且左右子树的高度差的绝对值不超过1。AVL树是⼀颗高度平衡搜索⼆叉树, 通过控制高度差去控…...
Cesium GIS项目关于湖泊识别与提取的实现
1. 引言 项目背景 随着遥感技术的发展,地理信息系统的应用越来越广泛。本项目旨在开发一个基于Cesium的地理信息系统,利用深度学习技术自动识别并显示湖泊的位置。 目标与意义 通过自动化处理大量遥感影像数据,提高湖泊监测的效率和准确性,为水资源管理和环境保护提供支…...
两个圆形 一个z里面一个z外面,z里面的大,颜色不同 html
两个圆形 一个z里面一个z外面,z里面的大,颜色不同 html <!DOCTYPE html> <html> <head> <style> .outer-circle {width: 150px;height: 150px;border-radius: 50%;background-color: #ff9999; /* 外圆的颜色 */position: relat…...
【Power Query】M函数-table
M函数-table 添加列(AddColumn):条件语句(If..then..else):容错语句(try..otherwise): 排序(ReorderColumns):筛选(Selec…...
uni-app 封装websocket 心跳检测,开箱即用
class websocketUtils {constructor(url, needbeat, options {}) {this.needbeat needbeat;this.url url;this.options options;this.ws null;this.heartbeatInterval options.heartbeatInterval || 10000; // 心跳间隔,默认为10秒 this.reconnectInterval …...
ASP.NET Core8.0学习笔记(十九)——EF Core DbSet
一、DbSet概述 1.DbSet提供了通过DbContext对表进行查询操作的路径。DbSet对应的属性名称将默认映射为实体T的表名。 2.使用DbSet<T>进行查询的方法: (1)直接在DbContext中创建对应的DbSet<T>属性 (2)使用DbSet DbContext.Set<T>方法操作数据表。…...
Android Camera 预览角度和拍照保存图片角度相关
–基于Android R(11) 关于Camera Camera Framework 的架构 Android Camera Framework 是一个分层架构,由以下组件组成: HAL(硬件抽象层): HAL 抽象底层相机硬件,提供与不同设备相机进行交互的标准接口.CameraService : Camera…...
新手如何使用Qt——方法使用
前言 那么这篇文章其实是我在使用Qt的过程当中呢,我发现在Qt使用过程中,在我理解信号和槽这个概念后,在编写槽函数数的时候,发现了自身存在的问题,我的难点是在于当我在编写槽函数的时候,我知道这个槽函数是…...
友元运算符重载函数
目录 1.定义友元运算符重载函数的语法形式 2.双目运算符重载 3.单目运算符重载 1.定义友元运算符重载函数的语法形式 (1)在类的内部,定义友元运算符重载函数的格式如下: friend 函数类型 operator 运算符(形参表&a…...
从0开始实现es6 promise类
主要由基础实现和静态类的实现两部分组成。 1 基础实现(不含静态类) 1.1 使用类实现完成构造函数 实现代码如下,构造函数传入一个回调函数,定义resolve和reject函数,将两个函数作为参数执行回调函数。 // 1. 使用类实…...
XML 编码
XML 编码 XML(可扩展标记语言)是一种用于存储和传输数据的标记语言。它由万维网联盟(W3C)开发,旨在提供一种标准的方式来结构化、存储和传输数据。XML的设计目标是既易于人类阅读,也易于机器解析。 XML的…...
AI周报(9.22-9.28)
AI应用-Siipet宠物沟通师 Siipet是一款由SiiPet公司推出的创新宠物行为分析相机,旨在通过尖端技术加深宠物与主人之间的情感联系。这款相机利用先进的AI算法,能够自动识别和分析家中宠物的行为,并提供定制化的护理建议。 SiiPet相机的核心功…...
基于RealSense D435相机实现手部姿态重定向
基于Intel RealSense D435相机和MediaPipe的手部姿态检测,进一步简单实现手部姿态与机器人末端的重定向,获取手部的6D坐标(包括位置和姿态)。 假设已经按照【基于 RealSenseD435i相机实现手部姿态检测】配置好所需的库和环境&…...
js中防抖 debounce 节流 throttle 原理 从0手动实现
1 防抖 高频触发事件时,执行损耗高的操作,连续触发过程中,只执行最后一次。 高频事件:input scroll resize等。损耗高:网络请求、dom操作。 实现防抖步骤:1.在回调函数中判断timer是否存在,存在…...
AIGC: 10 AI转文服务器的搭建过程记录
上图是台风席卷城市,现在企业的服务基本都是混合部署,云计算厂商的机房往往可以提供比较好的保护,一般在地下,扛多少级地震,扛多少级台风,而自建机房,往往写字楼经常停电,网络运营上…...
性能测试1初步使用Jmeter
当你看到这边文章的时候,详细你已经知道啥是性能测试,以及也听说过Jmeter了,所以不过多介绍,这里,只是帮助你快速的使用Jmeter来测试接口。 1获取安装包 官网下载地址:https://jmeter.apache.org/downloa…...
OpenGL ES 绘制一个三角形(2)
OpenGL ES 绘制一个三角形(2) 简述 本节我们基于Android系统,使用OpenGL ES来实现绘制一个三角形。在OpenGL ES里,三角形是一个基础图形,其他的图形都可以使用三角形拼接而成,所以我们就的案例就基于这个开始。 在Android系统中…...
QT----Creater14.0,qt5.15无法启动调试,Launching GDB Debugger报红
问题描述 使用QT Creater 14.0 和qt5.15,无法启动调试也没有报错,加载debugger报红 相关文件都有 解决方案 尝试重装QT,更换版本5.15.2,下载到文件夹,shift鼠标右键打开powershell输入 .\qt-online-installer-windows-x64-4.8.0.exe --mirror http://mirrors.ustc.edu.cn…...
初试React前端框架
文章目录 一、React概述二、React核心特性1、组件化设计2、虚拟DOM3、生态系统 三、实例操作1、准备工作2、创建项目结构3、启动项目4、编写React组件5、添加React样式6、运行项目,查看效果 四、实战小结 一、React概述 大家好,今天我们将一起探索React…...
华为OD机试真题---手机App防沉迷系统
题目概述 智能手机在方便我们生活的同时,也侵占了大量时间。手机App防沉迷系统旨在帮助用户合理规划手机App使用时间,确保在正确的时间做正确的事。系统的主要功能包括: 在一天24小时内,可注册每个App的允许使用时段。一个时段只…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
