`

数据结构 二叉树(B树)

 
阅读更多

BTree

特征:

1.一个节点最多只有两个子节点,其中左子节点的关键字小于这个节点,右子节点的关键字大于等于该节点。

2.执行查找,插入,删除的时间复杂度都是:O(logN)。

3.遍历有中序,前序,后序。前,中和后只是在递归的时候先输出左子,自己或右子的顺序。可以通过中排序,按左子,自己,右子的顺序就是升序,反之则是降序。

4.最大值是树的右边底层叶子;最小值是左边底层叶子。

 

JAVA代码实现:

 

 

Java代码  收藏代码
  1. package org.acooly.datastructure.btree;  
  2.   
  3. import java.util.Random;  
  4.   
  5. /** 
  6.  * 特征:一个节点的左子节点的关键字小于这个节点,右子节点的关键字大于等于该节点。 
  7.  *  
  8.  * @author zhangpu 
  9.  *  
  10.  */  
  11. public class BinaryTree {  
  12.   
  13.     /** 根节点 */  
  14.     private Node root;  
  15.   
  16.     /** 
  17.      * 查找 
  18.      *  
  19.      * @param key 
  20.      * @return 
  21.      */  
  22.     public Node find(int key) {  
  23.         if (root == null) {  
  24.             return null;  
  25.         }  
  26.         Node current = root;  
  27.         while (current.getKey() != key) {  
  28.             if (key < current.getKey()) {  
  29.                 // 小于本节点在左边  
  30.                 current = current.getLeftNode();  
  31.             } else {  
  32.                 // 大于等于本节点在右边  
  33.                 current = current.getRightNode();  
  34.             }  
  35.             if (current == null) {  
  36.                 // 搜索到最后叶子为空,表示没有找到  
  37.                 return null;  
  38.             }  
  39.         }  
  40.         return current;  
  41.     }  
  42.   
  43.     public Node getParent(int key) {  
  44.         if (root == null) {  
  45.             return null;  
  46.         }  
  47.         Node current = root;  
  48.         Node parent = root;  
  49.         while (current.getKey() != key) {  
  50.             if (key < current.getKey()) {  
  51.                 // 小于本节点在左边  
  52.                 parent = current;  
  53.                 current = current.getLeftNode();  
  54.             } else {  
  55.                 // 大于等于本节点在右边  
  56.                 parent = current;  
  57.                 current = current.getRightNode();  
  58.             }  
  59.             if (current == null) {  
  60.                 // 搜索到最后叶子为空,表示没有找到  
  61.                 return null;  
  62.             }  
  63.         }  
  64.         return parent;  
  65.     }  
  66.   
  67.     /** 
  68.      * 插入 
  69.      *  
  70.      * @param key 
  71.      * @param value 
  72.      */  
  73.     public void insert(int key, Object value) {  
  74.         Node node = new Node(key, value);  
  75.         if (root == null) {  
  76.             root = node;  
  77.             return;  
  78.         }  
  79.         Node current = root;  
  80.         while (true) {  
  81.             if (key < current.getKey()) {  
  82.                 if (current.getLeftNode() == null) {  
  83.                     current.setLeftNode(node);  
  84.                     return;  
  85.                 } else {  
  86.                     current = current.getLeftNode();  
  87.                 }  
  88.             } else {  
  89.                 if (current.getRightNode() == null) {  
  90.                     current.setRightNode(node);  
  91.                     return;  
  92.                 } else {  
  93.                     current = current.getRightNode();  
  94.                 }  
  95.             }  
  96.         }  
  97.   
  98.     }  
  99.   
  100.     /** 
  101.      * 中遍历(升序) 
  102.      *  
  103.      * @param startNode 
  104.      */  
  105.     public void inOrderAsc(Node startNode) {  
  106.   
  107.         if (startNode != null) {  
  108.             inOrderAsc(startNode.getLeftNode());  
  109.             System.out.println(startNode);  
  110.             inOrderAsc(startNode.getRightNode());  
  111.         }  
  112.   
  113.     }  
  114.   
  115.     /** 
  116.      * 中遍历(降序) 
  117.      *  
  118.      * @param startNode 
  119.      */  
  120.     public void inOrderDesc(Node startNode) {  
  121.         if (startNode != null) {  
  122.             inOrderDesc(startNode.getRightNode());  
  123.             System.out.println(startNode);  
  124.             inOrderDesc(startNode.getLeftNode());  
  125.         }  
  126.   
  127.     }  
  128.   
  129.     /** 
  130.      * 最大值 算法:树中最底层的右子叶 
  131.      *  
  132.      * @return 
  133.      */  
  134.     public Node getMax() {  
  135.         Node current = root;  
  136.         while (current.getRightNode() != null) {  
  137.             current = current.getRightNode();  
  138.         }  
  139.         return current;  
  140.     }  
  141.   
  142.     /** 
  143.      * 算法:树中最底层的左子叶 
  144.      *  
  145.      * @return 
  146.      */  
  147.     public Node getMin() {  
  148.         return getMin(root);  
  149.     }  
  150.   
  151.     /** 
  152.      * 指定节点的最小节点,如果指定节点为root,则是树的最小节点 
  153.      *  
  154.      * @param localRoot 
  155.      * @return 
  156.      */  
  157.     private Node getMin(Node localRoot) {  
  158.         Node current = localRoot;  
  159.         while (current.getLeftNode() != null) {  
  160.             current = current.getLeftNode();  
  161.         }  
  162.         return current;  
  163.     }  
  164.   
  165.     /** 
  166.      * 删除节点存在3中情况 <li>目标节点是叶子:直接删除,置为null <li> 
  167.      * 目标节点只有一个子节点:如果目标节点是在父节点的左边,直接使用子节点作为父节点的左子,反正则为右子。 <li> 
  168.      * 目标节点有两个子节点:找到后继节点,作为目标节点父节点的对应子节点。(后继:目标节点子节点中大于目标节点最小的个。路径:目标节点右子的最小节点。) 
  169.      *  
  170.      * @param key 
  171.      */  
  172.     public void delete(int key) {  
  173.   
  174.         Node target = find(key);  
  175.         if (target == null) {  
  176.             return;  
  177.         }  
  178.   
  179.         boolean leftExsit = (target.getLeftNode() != null ? true : false);  
  180.         boolean rightExsit = (target.getRightNode() != null ? true : false);  
  181.         // 第一种情况,目标是叶子,直接设置为null  
  182.         if (!leftExsit && !rightExsit) {  
  183.             target = null;  
  184.             return;  
  185.         }  
  186.   
  187.         // 获得目标的父节点  
  188.         Node parent = getParent(key);  
  189.         Node child = null;  
  190.         if (leftExsit != rightExsit) {  
  191.             // 第二种情况:只有一个子  
  192.             child = (leftExsit ? target.getLeftNode() : target.getRightNode());  
  193.         } else {  
  194.             // 第三种情况:有两个子  
  195.             Node rightChild = target.getRightNode();  
  196.             child = getMin(rightChild);  
  197.             getParent(child.getKey()).setLeftNode(null);  
  198.             child.setRightNode(rightChild);  
  199.         }  
  200.   
  201.         if (parent == null) {  
  202.             root = child;  
  203.             target = null;  
  204.             return;  
  205.         }  
  206.   
  207.         if (parent.getLeftNode() != null && target.getKey() < parent.getLeftNode().getKey()) {  
  208.             // 目标是父的左子  
  209.             parent.setLeftNode(child);  
  210.         } else {  
  211.             // 目标是父的右子  
  212.             parent.setRightNode(child);  
  213.         }  
  214.         target = null;  
  215.     }  
  216.   
  217.     public Node getRoot() {  
  218.         return root;  
  219.     }  
  220.   
  221.     public static void main(String[] args) {  
  222.         BinaryTree tree = new BinaryTree();  
  223.         Random random = new Random();  
  224.         // INSERT  
  225.         for (int i = 1; i <= 10; i++) {  
  226.             int key = random.nextInt(100);  
  227.             tree.insert(key, "value" + key);  
  228.         }  
  229.         int key = 0;  
  230.         tree.insert(key, "value" + key);  
  231.         System.out.println("TARGET key: " + key);  
  232.         // FIND  
  233.         System.out.println("FIND: " + tree.find(key));  
  234.         // GETPARENT  
  235.         System.out.println("PARENT: " + tree.getParent(key));  
  236.         // MIX  
  237.         System.out.println("MAX: " + tree.getMax());  
  238.         // MIN  
  239.         System.out.println("MIN: " + tree.getMin());  
  240.         tree.delete(key);  
  241.         System.out.println();  
  242.         System.out.println("中遍历(升序):");  
  243.         tree.inOrderAsc(tree.getRoot());  
  244.         System.out.println("中遍历(降序):");  
  245.         tree.inOrderDesc(tree.getRoot());  
  246.     }  
  247.   
  248. }  

   节点类:

 

Java代码  收藏代码
  1. package org.acooly.datastructure.btree;  
  2.   
  3. /** 
  4.  * BTree 节点 
  5.  *  
  6.  * @author zhangpu 
  7.  *  
  8.  */  
  9. public class Node {  
  10.   
  11.     /** 节点KEY */  
  12.     private int key;  
  13.     private Object value;  
  14.     /** 左子节点 */  
  15.     private Node leftNode;  
  16.     /** 右子节点 */  
  17.     private Node rightNode;  
  18.   
  19.     public Node() {  
  20.         super();  
  21.     }  
  22.   
  23.     public Node(int key, Object value) {  
  24.         super();  
  25.         this.key = key;  
  26.         this.value = value;  
  27.     }  
  28.   
  29.     public int getKey() {  
  30.         return key;  
  31.     }  
  32.   
  33.     public void setKey(int key) {  
  34.         this.key = key;  
  35.     }  
  36.   
  37.     public Node getLeftNode() {  
  38.         return leftNode;  
  39.     }  
  40.   
  41.     public void setLeftNode(Node leftNode) {  
  42.         this.leftNode = leftNode;  
  43.     }  
  44.   
  45.     public Node getRightNode() {  
  46.         return rightNode;  
  47.     }  
  48.   
  49.     public void setRightNode(Node rightNode) {  
  50.         this.rightNode = rightNode;  
  51.     }  
  52.   
  53.     public Object getValue() {  
  54.         return value;  
  55.     }  
  56.   
  57.     public void setValue(Object value) {  
  58.         this.value = value;  
  59.     }  
  60.   
  61.     @Override  
  62.     public String toString() {  
  63.         return String.valueOf(key) + "=" + value;  
  64.     }  
  65.       
  66.     @Override  
  67.     public boolean equals(Object obj) {  
  68.         if(obj instanceof Node){  
  69.             Node n = (Node)obj;  
  70.             if(n.getKey() != getKey()){  
  71.                 return false;  
  72.             }  
  73.         }else{  
  74.             return false;  
  75.         }  
  76.         return true;  
  77.     }  
  78.   
  79. }  

分享到:
评论

相关推荐

    COMSOL激光增材制造技术:热流力三场耦合模型的构建与模拟研究,COMSOL激光增材制造中热-流-力三场耦合模型的研究与应用:基于固体传热、固体力学、层流和动网格技术的多物理场分析,comsol激光

    COMSOL激光增材制造技术:热流力三场耦合模型的构建与模拟研究,COMSOL激光增材制造中热-流-力三场耦合模型的研究与应用:基于固体传热、固体力学、层流和动网格技术的多物理场分析,comsol激光增材制造热-流-力三场偶合模型 选用固体传热,固体力学,层流和动网格,考虑热物性以及马兰戈尼效应、表面张力,相变潜热,热对流和热辐射等 【软件工具】COMSOL5.6 【备注】,comsol三维模型 ,核心关键词:comsol; 激光增材制造; 热-流-力三场偶合模型; 固体传热; 固体力学; 层流; 动网格; 热物性; 马兰戈尼效应; 表面张力; 相变潜热; 热对流; 热辐射; COMSOL5.6; 三维模型。,COMSOL 5.6激光增材制造三场耦合模型

    基于PLL的SMO滑模观测器算法在永磁同步电机无传感器矢量控制中的应用及其与反正切SMO的对比:有效消除转速抖动,基于PLL的SMO滑模观测器算法在永磁同步电机无传感器矢量控制中的应用及其与反正切SM

    基于PLL的SMO滑模观测器算法在永磁同步电机无传感器矢量控制中的应用及其与反正切SMO的对比:有效消除转速抖动,基于PLL的SMO滑模观测器算法在永磁同步电机无传感器矢量控制中的应用及其与反正切SMO的对比:有效消除转速抖动,基于PLL的SMO滑模观测器算法,永磁同步电机无传感器矢量控制,跟基于反正切的SMO做对比,可以有效消除转速的抖动。 ,基于PLL的SMO滑模观测器算法; 永磁同步电机无传感器矢量控制; 反正切SMO; 转速抖动消除。,基于PLL SMO滑模观测器:永磁同步电机无传感器矢量控制新算法,优化抖动消除效能

    【毕业设计】java-springboot+vue个人云盘管理系统实现源码(完整前后端+mysql+说明文档+LunW).zip

    【毕业设计】java-springboot+vue个人云盘管理系统实现源码(完整前后端+mysql+说明文档+LunW).zip

    【语音识别】基于matlab自适应滤波器LMS算法鸟类物种识别【含Matlab源码 9977期】.mp4

    海神之光上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    【毕业设计】java-springboot-vue电影推荐系统实现源码(完整前后端-mysql-说明文档-LunW).zip

    【毕业设计】java-springboot-vue电影推荐系统实现源码(完整前后端-mysql-说明文档-LunW).zip

    基于OpenCV和Python的实时口罩识别系统:支持摄像头与图片检测,界面简洁操作便捷,基于OpenCV的口罩识别系统 相关技.

    基于OpenCV和Python的实时口罩识别系统:支持摄像头与图片检测,界面简洁操作便捷,基于OpenCV的口罩识别系统 相关技术:python,opencv,pyqt (请自行安装向日葵远程软件,以便提供远程帮助) 软件说明:读取用户设备的摄像头,可实时检测画面中的人的口罩佩戴情况,并给予提示。 有基础的同学,可稍作修改,检测图片。 第一张为运行主界面。 第二张为部分代码截图。 第三和第四张为运行界面。 ,基于OpenCV的口罩识别系统; Python; OpenCV; PyQt; 远程协助; 摄像头读取; 实时检测; 口罩佩戴情况提示; 代码截图; 运行界面。,"基于OpenCV与Python的口罩识别系统:实时检测与提醒"

    Git与GitHub入门指南:版本控制、协作开发及基础命令教程

    内容概要:本文是一份关于 Git 和 GitHub 的入门指南,详细介绍了一整套从安装到进阶使用的完整流程。文章首先阐述了版本控制的重要性,并解释了 Git 的特点和优势。接着逐步介绍了 Git 和 GitHub 的使用方法,包括安装设置 Git、创建和管理 GitHub 账户、创建和克隆仓库,以及日常操作如提交、推送、拉取、分支管理和处理冲突的具体指令和操作步骤。还涉及到高级主题如合并请求、持续集成等功能的介绍,帮助读者深入了解 Git 和 GitHub 的应用范围和最佳实践。 适用人群:适用于刚开始接触版本控制系统的初学者,特别是那些正在寻找 Git 和 GitHub 实际操作指导的学生和技术爱好者。 使用场景及目标:①为刚踏入软件开发领域的新人提供详尽的基础教学,使其能够快速理解和掌握必要的技能;②指导已有一定经验但仍想进一步深化理解的开发人员如何优化日常工作流程;③促进团队合作效率提升,通过具体的实例演示如何利用版本控制系统协调多人协作。 其他说明:随着 Git 和 GitHub 成为现代软件开发的标准工具之一,这份资料不仅涵盖了关键知识点,而且配有多图例解析和实操练习,确保每个阶段的学习都能得到良好反馈和支持。读者可以通过动手实践来巩固所学知识,在实践中遇到困难也能及时参考本文获得解决方案。

    python安装-16. 使用指定序列和数值创建一个字典-分配伴侣.py

    python安装-16. 使用指定序列和数值创建一个字典——分配伴侣.py

    Python+OpenCV魔方识别系

    本研究的目的是基于Python和OpenCV开发一个魔方识别系统,并提供相应的源码和部署教程。通过该系统,用户可以将魔方的图像输入,系统可以自动识别魔方的状态,并给出相应的还原方案。具体来说,本研究的主要内容包括以下几个方面: 图像预处理:通过使用OpenCV提供的图像处理算法,对输入的魔方图像进行预处理,包括图像去噪、边缘检测、图像分割等操作,以提高后续的识别准确率。 特征提取与模式识别:通过使用OpenCV提供的特征提取算法,对预处理后的图像进行特征提取,以获取魔方的状态信息。然后,通过机器学习算法,对提取到的特征进行模式识别,以确定魔方的状态。 还原方案生成:根据识别到的魔方状态,使用经典的还原算法,生成相应的还原方案。通过该方案,用户可以轻松地还原魔方,提高解决效率。

    基于Springboot与Vue.js的WMS仓库管理系统源码详解:前后端分离架构下的Java实践与功能详述,基于Springboot和Vue的前后端分离WMS仓库管理系统源码,详细功能参考详情 ,S

    基于Springboot与Vue.js的WMS仓库管理系统源码详解:前后端分离架构下的Java实践与功能详述,基于Springboot和Vue的前后端分离WMS仓库管理系统源码,详细功能参考详情。,Springboot vue仓库管理系统源码Java 前后端分离 WMS仓库管理 BS 功能见详情 ,Springboot; Vue; 仓库管理系统; 源码; Java; 前后端分离; WMS仓库管理; BS; 功能详情,Springboot+Vue仓库管理系统源码:前后端分离的WMS管理BS应用

    用AI学安卓游戏开发1-控制小球上下左右移动2代码

    用AI学安卓游戏开发1——控制小球上下左右移动2代码, 初始化小球随机自有移动,遇到屏幕边缘反弹,摇杆介入后小球停止自有移动,按照摇杆控制方向移动。

    【图像融合】基于matlab拉普拉斯方法水下图像增强融合【含Matlab源码 9983期】复现.mp4

    海神之光上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    【图像加密】基于matlab差分扩展缩略图保持加密【含Matlab源码 9692期】.mp4

    海神之光上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    【图像重建】CT图像重建【含Matlab源码 8035期】.md

    CSDN Matlab武动乾坤上传的资料均是完整代码运行出的仿真结果图,可见完整代码亲测可用,适合小白; 1、完整的代码内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主或扫描博客文章底部QQ名片; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    基于ATP-EMTP的110kV海底电缆与架空线雷击过电压仿真分析与研究,基于ATP-EMTP的110kV海底电缆与架空线雷击过电压仿真分析与研究,110kV海底电缆-架空线雷击过电压ATP-EMTP

    基于ATP-EMTP的110kV海底电缆与架空线雷击过电压仿真分析与研究,基于ATP-EMTP的110kV海底电缆与架空线雷击过电压仿真分析与研究,110kV海底电缆-架空线雷击过电压ATP-EMTP仿真分析 ,核心关键词: 110kV海底电缆; 架空线; 雷击过电压; ATP-EMTP仿真分析; 分析。 关键词用分号分隔,如上所示。,雷击过电压仿真分析:110kV海底电缆及架空线ATP-EMTP研究

    基于800kV高压直流输电的VSC-HVDC仿真模型研究:控制策略与性能分析,基于800kV-VSC-HVDC的直流输电仿真模型研究:深入探讨控制结构与电压稳定性,800kV-VSC-HVDC直流输电

    基于800kV高压直流输电的VSC-HVDC仿真模型研究:控制策略与性能分析,基于800kV-VSC-HVDC的直流输电仿真模型研究:深入探讨控制结构与电压稳定性,800kV-VSC-HVDC直流输电仿真模型(Matlab) 流器拓扑:VSC两电平流器 电压等级:直流800kV,交流500kV 控制结构:逆变侧定有功控制与电流内环PI+前馈解耦,整流侧定直流电压与电流内环+PI前馈解耦; 输电距离:100km; 双端电压电流均为对称的三相电压电流; 直流电压稳定在800kV; 双端网侧THD<2% 电子资料, ,800kV; VSC HVDC; 直流输电仿真模型; Matlab; VSC两电平换流器; 直流电压稳定; 逆变侧定有功控制; 电流内环PI+前馈解耦; 整流侧定直流电压与电流内环; 输电距离; 双端电压电流对称; 双端网侧THD<2%。,Matlab仿真模型:800kV VSC两电平换流器HVDC输电系统

    【电池】基于matlab太阳能电池漂移扩散【含Matlab源码 11051期】.mp4

    海神之光上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    【毕业设计】java-springboot-vue电商应用系统实现源码(完整前后端-mysql-说明文档-LunW).zip

    【毕业设计】java-springboot-vue电商应用系统实现源码(完整前后端-mysql-说明文档-LunW).zip

    【运动学】基于matlab追踪法导弹打飞机仿真【含Matlab源码 11016期】.mp4

    海神之光上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    uniapp使用蓝牙通信示例

    uniapp使用蓝牙通信示例

Global site tag (gtag.js) - Google Analytics