【C语言】数据结构——链式二叉树实例探究

💗个人主页💗
⭐个人专栏——数据结构学习⭐
💫点击关注🤩一起学习C语言💯💫

导读:

我们在前面学习了单链表,顺序表,栈和队列,小堆。
今天我们来学习链式二叉树
关注博主或是订阅专栏,掌握第一消息。

1. 链式二叉树的概念和结构

链式二叉树(Linked Binary Tree)是一种基于链表实现的二叉树结构。在链式二叉树中,每个节点由三个部分组成:数据、左子节点和右子节点。
在这里插入图片描述

1.1 链式二叉树的特点

链式二叉树的特点包括:

  1. 每个节点都有一个数据项,可以是任意类型的数据。
  2. 每个节点都有一个左子节点和一个右子节点。如果某个节点没有左子节点或右子节点,对应的子节点指针就为空。
  3. 子节点可以是空的,也可以是另一个链式二叉树的根节点。这就构成了二叉树的递归结构。

链式二叉树的优点是可以动态地插入和删除节点,不需要预先指定树的大小。
同时,链式二叉树的节点可以随意分配在内存中,不需要连续的存储空间。
缺点是相对于数组实现的二叉树,链式二叉树需要额外的指针来连接节点,因此会占用更多的内存空间。

1.2 链式二叉树的遍历

链式二叉树的遍历方式有三种:前序遍历、中序遍历和后序遍历。

前序遍历先访问根节点,然后按照左子树、右子树的顺序遍历;
中序遍历先访问左子树,然后访问根节点,最后访问右子树;
后序遍历先访问左子树,然后访问右子树,最后访问根节点。

2. 二叉树的代码实现

2.1 创建二叉树

我们先创建一个六个节点的二叉树


typedef int BTDataType;
//typedef char BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}TreeNode;//开辟空间并赋值
TreeNode* BuyTreeNode(int x)
{TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));assert(node);node->data = x;node->left = NULL;node->right = NULL;return node;
}
TreeNode* CreateTree()
{TreeNode* node1 = BuyTreeNode(7);TreeNode* node2 = BuyTreeNode(9);TreeNode* node3 = BuyTreeNode(30);TreeNode* node4 = BuyTreeNode(25);TreeNode* node5 = BuyTreeNode(66);TreeNode* node6 = BuyTreeNode(88);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}

在这里插入图片描述

2.2 前序遍历

前序遍历:访问根结点的操作发生在遍历其左右子树之前。
**注意:**左节点全部访问完之后才访问右节点。
遇到NULL,则返回,否则继续调用,直到遇到NULL

//前序遍历
void PrevOrder(TreeNode* root)
{if (root == NULL){printf("NULL ");return NULL;}//先访问根节点printf("%d ", root->data);//之后访问左节点和右节点PrevOrder(root->left);PrevOrder(root->right);
}

在这里我们把空值也打印了出来
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 中序遍历

中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
**注意:**是把一个节点的所有左子树访问完之后再去打印值,最后再访问右子树。

//中序遍历
void InOrder(TreeNode* root)
{if (root == NULL){printf("NULL ");return NULL;}//访问完所有左子树后再打印值InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4 计算节点个数

计算链式二叉树的节点个数可以通过递归的方式实现。

  1. 若二叉树为空,则节点个数为0。
  2. 若二叉树不为空,则节点个数为根节点的个数加上左子树的节点个数和右子树的节点个数。
  3. 使用递归对左子树和右子树分别计算节点个数。
  4. 返回根节点的个数加上左子树和右子树的节点个数。
// 节点个数
int TreeSize(TreeNode* root)
{//如果为空返回0if (root == NULL){return 0;}//不为空调用左右节点,每次调用都会加一return TreeSize(root->left)+ TreeSize(root->right) + 1;
}

在这里插入图片描述
在这里插入图片描述

2.5 计算叶子节点的个数

叶子节点是指在树中没有子节点的节点,可以通过遍历树的方式来计算叶子节点的个数。
以下是计算叶子节点个数的递归算法:

  1. 如果树为空,则叶子节点个数为0。
  2. 如果树只有一个节点,则叶子节点个数为1。
  3. 否则,叶子节点个数等于左子树的叶子节点个数加上右子树的叶子节点个数。
// 叶子节点的个数
int TreeLeafSize(TreeNode* root)
{if (root == NULL){return 0;}//如果该节点的左节点和右节点都为空if (!(root->left) && !(root->right)){return 1;}return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

在这里插入图片描述

2.6 计算树的高度

计算树的高度可以使用递归的方法来完成。一个树的高度可以定义为从根节点到最远叶子节点的边数。

// 树的高度
int TreeHight(TreeNode* root)
{if (root == NULL){return 0;}//返回较大的一个return fmax(TreeHight(root->left), TreeHight(root->right)) + 1;
}

在这里插入图片描述

2.7 计算树第k层节点个数

树的第k层节点个数取决于树的结构,不同的树的第k层节点个数可能不同。一般情况下,树的第k层节点个数为k层的节点数减去k-1层的节点数。

int TreeLevelK(TreeNode* root, int k)
{assert(k > 0);if (root == NULL){return 0;}if (k == 1){return 1;}return TreeLevelK(root->left, k - 1) + TreeLevelK(root->right, k - 1);
}

在这里插入图片描述
k=1时,说明到达了k层
在这里插入图片描述

2.8 二叉树查找值为x的节点

二叉树查找值为x的节点可以通过递归来实现,具体步骤如下:

  1. 如果当前节点为空,则返回空。
  2. 如果当前节点的值等于x,则返回当前节点。
  3. 如果该节点的值不等于x,递归在左子树中查找值为x的节点。
  4. 如果该左子树节点的值不等于x,递归在右子树中查找值为x的节点。
TreeNode* TreeFind(TreeNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}//另设记录函数调用返回的值,再判断是否为kongTreeNode* ret1 = TreeFind(root->left, x);if (ret1){return ret1;}TreeNode* ret2 = TreeFind(root->right, x);if (ret2){return ret2;}return NULL;
}

在这里插入图片描述

2.9 通过前序遍历的数组构建二叉树

通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树,通过遍历我们要建立如下效果:
在这里插入图片描述

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
TreeNode* TreeCreate(char* a, int* pi)
{if (a[*pi] == '#'){(*pi)++;return NULL;}TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));if (root == NULL){perror("malloc fail");exit(-1);}root->data = a[(*pi)++];root->left = TreeCreate(a, pi);root->right = TreeCreate(a, pi);return root;
}
int main()
{char arr[] = "ABD##E#H##CF##G##";int i = 0;TreeNode* rootstr = TreeCreate(arr, &i);return 0;
}

2.10 层序遍历

链式二叉树的层序遍历可以通过使用队列来实现。具体步骤如下:

  1. 首先,将根节点入队。

  2. 进入循环,直到队列为空。

    • 从队列中取出一个节点,并将其值输出。
    • 如果该节点有左子节点,则将左子节点入队。
    • 如果该节点有右子节点,则将右子节点入队。
  3. 循环结束后,层序遍历完成。

//层序遍历
void LevelOrder(TreeNode* root)
{QNode q;QueueInit(&q);if (root){QueuePush(&q, root);}int levelSize = 1;while (!QueueEmpty(&q)){while (levelSize--){TreeNode* front = QueueFront(&q);QueuePop(&q);printf("%c ", front->data);if (front->left){QueuePush(&q, front->left);}if (front->right){QueuePush(&q, front->right);}}printf("\n");levelSize = QueueSize(&q);}printf("\n");QueueDestroy(&q);
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.11 判断一棵树是否是完全二叉树

完全二叉树是指除了最后一层外,其他层的节点都是满的,且最后一层的节点从左到右依次填满。因此,我们可以通过遍历树的节点来判断是否是完全二叉树。

  1. 使用层次遍历的方法遍历树的节点。
  2. 当遇到第一个为空的节点时,停止遍历。
  3. 继续遍历树的节点,如果还存在非空节点,那么该树不是完全二叉树。
  4. 如果遍历完所有节点,都没有发现非空节点,那么该树是完全二叉树。
//判断一棵树是否是完全二叉树
bool TreeComplete(TreeNode* root)
{Queue q;QueueInit(&q);if (root){QueuePush(&q, root);}while (!QueueEmpty(&q)){TreeNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){break;}QueuePush(&q, front->left);QueuePush(&q, front->right);}// 前面遇到空以后,后面还有非空就不是完全二叉树while (!QueueEmpty(&q)){TreeNode* front = QueueFront(&q);QueuePop(&q);if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

2.12 二叉树销毁

需要把每一个节点都销毁,值得注意的是,要从最下层的节点开始销毁,而不是根节点

//二叉树销毁
void DestroyTree(TreeNode* root)
{if (root == NULL){return NULL;}DestroyTree(root->left);DestroyTree(root->right);free(root);
}

3. 代码整理

该代码的层序遍历导入了我们之前写的队列

Queue.h

#define _CRT_SECURE_NO_WARNINGS #pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>// 链式结构:表示队列 
typedef int QDataType;
typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;// 队列的结构 
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;// 初始化队列 
void QueueInit(Queue* pq);// 销毁队列 
void QueueDestroy(Queue* pq);// 队尾入队列 
void QueuePush(Queue* pq, QDataType x);// 队头出队列
void QueuePop(Queue* pq);// 获取队列头部元素 
QDataType QueueFront(Queue* pq);// 获取队列队尾元素
QDataType QueueBack(Queue* pq);// 检测队列是否为空,如果为空返回true,如果非空返回false 
bool QueueEmpty(Queue* pq);// 获取队列中有效元素个数 
int QueueSize(Queue* pq);

Queue.c

#include "Queue.h"// 初始化队列 
void QueueInit(Queue* pq)
{pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}// 销毁队列 
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead->next;while (cur){free(pq->phead);pq->phead = cur;cur = cur->next;}cur = NULL;pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}// 队尾入队列 
void QueuePush(Queue* pq, QDataType x)
{//开辟新空间QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}// 队头出队列
void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead);QNode* tmp = pq->phead;pq->phead = pq->phead->next;free(tmp);tmp = NULL;if (pq->phead == NULL){pq->ptail = NULL;}pq->size--;
}// 获取队列头部元素
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}// 获取队列队尾元素
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->ptail);return pq->ptail->val;
}// 检测队列是否为空,如果为空返回true,如果非空返回false 
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}// 获取队列中有效元素个数 
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

study.c

#include "Queue.h"typedef int BTDataType;
//typedef char BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}TreeNode;TreeNode* BuyTreeNode(int x)
{TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));assert(node);node->data = x;node->left = NULL;node->right = NULL;return node;
}
TreeNode* CreateTree()
{TreeNode* node1 = BuyTreeNode(7);TreeNode* node2 = BuyTreeNode(9);TreeNode* node3 = BuyTreeNode(30);TreeNode* node4 = BuyTreeNode(25);TreeNode* node5 = BuyTreeNode(66);TreeNode* node6 = BuyTreeNode(88);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}//前序遍历
void PrevOrder(TreeNode* root)
{if (root == NULL){printf("NULL ");return NULL;}//先访问根节点printf("%d ", root->data);//之后访问左节点和右节点PrevOrder(root->left);PrevOrder(root->right);
}//中序遍历
void InOrder(TreeNode* root)
{if (root == NULL){printf("NULL ");return NULL;}//访问完所有左子树后再打印值InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}// 节点个数
int TreeSize(TreeNode* root)
{//如果为空返回0if (root == NULL){return 0;}//不为空调用左右节点,每次调用都会加一return TreeSize(root->left)+ TreeSize(root->right) + 1;
}// 叶子节点的个数
int TreeLeafSize(TreeNode* root)
{if (root == NULL){return 0;}//如果该节点的左节点和右节点都为空if (!(root->left) && !(root->right)){return 1;}return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}// 树的高度
int TreeHight(TreeNode* root)
{if (root == NULL){return 0;}//返回较大的一个return fmax(TreeHight(root->left), TreeHight(root->right)) + 1;
}//树第k层节点个数
int TreeLevelK(TreeNode* root, int k)
{assert(k > 0);if (root == NULL){return 0;}if (k == 1){return 1;}return TreeLevelK(root->left, k - 1) + TreeLevelK(root->right, k - 1);
}// 二叉树查找值为x的节点
TreeNode* TreeFind(TreeNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}//另设记录函数调用返回的值,再判断是否为kongTreeNode* ret1 = TreeFind(root->left, x);if (ret1){return ret1;}TreeNode* ret2 = TreeFind(root->right, x);if (ret2){return ret2;}return NULL;
}// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
TreeNode* TreeCreate(char* a, int* pi)
{if (a[*pi] == '#'){(*pi)++;return NULL;}TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));if (root == NULL){perror("malloc fail");exit(-1);}root->data = a[(*pi)++];root->left = TreeCreate(a, pi);root->right = TreeCreate(a, pi);return root;
}//二叉树销毁
void DestroyTree(TreeNode* root)
{if (root == NULL){return NULL;}DestroyTree(root->left);DestroyTree(root->right);free(root);
}//层序遍历
void LevelOrder(TreeNode* root)
{QNode q;//初始化队列QueueInit(&q);if (root){//把根节点入队列QueuePush(&q, root);}//从1开始int levelSize = 1;while (!QueueEmpty(&q)){while (levelSize--){TreeNode* front = QueueFront(&q);QueuePop(&q);printf("%c ", front->data);//入左子树和右子树if (front->left){QueuePush(&q, front->left);}if (front->right){QueuePush(&q, front->right);}}printf("\n");//获取队列有效数据个数levelSize = QueueSize(&q);}printf("\n");QueueDestroy(&q);
}//判断一棵树是否是完全二叉树
bool TreeComplete(TreeNode* root)
{Queue q;QueueInit(&q);if (root){QueuePush(&q, root);}//遍历入队列while (!QueueEmpty(&q)){TreeNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){break;}QueuePush(&q, front->left);QueuePush(&q, front->right);}// 前面遇到空以后,后面还有非空就不是完全二叉树while (!QueueEmpty(&q)){TreeNode* front = QueueFront(&q);QueuePop(&q);if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}void Test1()
{TreeNode* root = CreateTree();printf("前序遍历:\n");PrevOrder(root);printf("\n");printf("中序遍历:\n");InOrder(root);printf("\n");printf("节点个数:%d\n", TreeSize(root));printf("叶子节点的个数:%d\n", TreeLeafSize(root));printf("树的高度:%d\n", TreeHight(root));printf("树第k层节点个数:%d\n", TreeLevelK(root, 3));int x = 0;printf("请输入想要查找的x值:》");scanf("%d", &x);printf("查找值为x的节点: %p\n", TreeFind(root, x));bool ret = TreeComplete(root);if (ret){printf("yes\n");}else{printf("no\n");}
}void Test2()
{char arr[] = "ABD##E#H##CF##G##";int i = 0;TreeNode* rootstr = TreeCreate(arr, &i);LevelOrder(rootstr);
}
int main()
{//Test1();Test2();return 0;
}

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

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

相关文章

MATLAB 主成分分析PCA拟合平面点云 (42)

MATLAB 主成分分析PCA拟合平面点云 (42) 一、算法介绍二、算法实现一、算法介绍 主成分分析(Principal Component Analysis,PCA)是一种常用的数据降维和特征提取技术。它的主要思想是通过线性变换将数据投影到一个新的坐标系,使得在新的坐标系中数据的方差最大化。在3D点…

java读取含有合并单元格的Excel

java读取含有合并单元格的Excel Excel如下&#xff1a; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.*;import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.…

springboot学习笔记(二)

1.Spring 和SpringBoot区别 2.Web开发入门 3.MVC模型 4.RequestMapping用法 5.RESTful 1.Spring 和SpringBoot区别 参考&#xff1a; 大家都懂Spring和SpringBoot的区别吗&#xff1f; - 知乎 https://www.zhihu.com/question/598494506/answer/3018702101 在学习了Spri…

Opencv实验合集——实验四:图片融合

1.概念 图像融合是将两个或多个图像结合在一起&#xff0c;创建一个新的图像的过程。这个过程的目标通常是通过合并图像的信息来获得比单个图像更全面、更有信息量的结果。图像融合可以在许多领域中应用&#xff0c;包括计算机视觉、遥感、医学图像处理等。 融合的方法有很多…

Docker 核心技术

Docker 定义&#xff1a;于 Linux 内核的 Cgroup&#xff0c;Namespace&#xff0c;以及 Union FS 等技术&#xff0c;对进程进行封装隔离&#xff0c;属于操作系统层面的虚拟化技术&#xff0c;由于隔离的进程独立于宿主和其它的隔离的进程&#xff0c;因此也称其为容器Docke…

系统设计架构——互联网案例

Netflix 的技术栈 移动和网络:Netflix 采用 Swift 和 Kotlin 来构建原生移动应用。对于其 Web 应用程序,它使用 React。 前端/服务器通信:Netflix 使用 GraphQL。 后端服务:Netflix 依赖 ZUUL、Eureka、Spring Boot 框架和其他技术。 数据库:Netflix 使用 EV 缓存、Cas…

关于“Python”的核心知识点整理大全25

目录 10.3.4 else 代码块、 10.3.5 处理 FileNotFoundError 异常 alice.py 在这个示例中&#xff0c;try代码块引发FileNotFoundError异常&#xff0c;因此Python找出与该错误匹配的 except代码块&#xff0c;并运行其中的代码。最终的结果是显示一条友好的错误消息&#x…

云计算:FusionCompute 通过 FreeNAS 添加SAN存储

目录 一、实验 1.环境准备 2.FusionCompute添加CNA 3.在存储中创建LUN资源映射给CNA节点 3.添加存储资源关联CNA主机节点 4.扫描存储资源 5.将存储设备添加为数据存储 二、问题 1.FusionCompute中存储如何分类 2.存储资源与存储设备有何区别 3.FusionCompute支持哪些…

线上环境如何正确配置 Django 的 DEBUG?

Author&#xff1a;rab Django Version&#xff1a;3.2 Python Version&#xff1a;3.9 目录 前言一、DEBUG True二、DEBUG False三、页面异常解决总结 前言 由于最近在学习 Django 的知识&#xff0c;于是尝试开发了一套 Blog 系统&#xff0c;在本地测试时是页面显示没问题…

零刻EQ12 N100 2.5G双网口 All In One新手教程

零刻EQ12 N100 2.5G双网口 All In One新手教程 前言1.硬件配置2.准备工作2.1. ESXI8.0U2镜像2.2. Rufus磁盘工具下载2.3. ikuai镜像下载2.4. StarWindConverter虚拟磁盘格式转换工具下载2.5. OpenWrt镜像下载2.6. 黑群晖RR引导镜像下载(DSM7.2)2.7. 需要准备的硬件2.8. 格式化需…

【ArcGIS微课1000例】0081:ArcGIS指北针乱码解决方案

问题描述&#xff1a; ArcGIS软件在作图模式下插入指北针&#xff0c;出现指北针乱码&#xff0c;如下图所示&#xff1a; 问题解决 下载并安装字体&#xff08;配套实验数据包0081.rar中获取&#xff09;即可解决该问题。 正常的指北针选择器&#xff1a; 专栏介绍&#xff…

【复杂网络分析与可视化】——通过CSV文件导入Gephi进行社交网络可视化

目录 一、Gephi介绍 二、导入CSV文件构建网络 三、图片输出 一、Gephi介绍 Gephi具有强大的网络分析功能&#xff0c;可以进行各种网络度量&#xff0c;如度中心性、接近中心性、介数中心性等。它还支持社区检测算法&#xff0c;可以帮助用户发现网络中的群组和社区结构。此…

设计模式——0前言目录

1 设计模式介绍 应当站在产品经理的角度来学习设计模式 是软件设计中常见问题的典型解决方案&#xff0c;可用于解决代码中反复出现的设计问题 学习效果一般的原因在于自己没有站在产品经理的角度学习&#xff0c;仅仅是为了学习怎么实现&#xff0c;用什么算法实现。 分类&…

pycharm运行正常,但命令行执行提示module不存在的多种解决方式

问题描述 在执行某个测试模块时出现提示&#xff0c;显示自定义模块data不存在&#xff0c;但是在PyCharm下运行正常。错误信息如下&#xff1a; Traceback (most recent call last):File "/run/channelnterface-autocase/testcases/test_chanel_detail.py", line 2…

JavaSE学习笔记 Day20

JavaSE学习笔记 Day20 个人整理非商业用途&#xff0c;欢迎探讨与指正&#xff01;&#xff01; 上一篇 文章目录 JavaSE学习笔记 Day20十七、数据结构与算法17.1算法17.1.1冒泡排序17.1.2选择排序17.1.3插入排序17.1.4三个排序的区别 17.2顺序表17.2.1顺序表代码实现17.2.2顺…

蜘点云原生之 KubeSphere 落地实践过程

作者&#xff1a;池晓东&#xff0c;蜘点商业网络服务有限公司技术总监&#xff0c;从事软件开发设计 10 多年&#xff0c;喜欢研究各类新技术&#xff0c;分享技术。 来源&#xff1a;本文由 11 月 25 日广州站 meetup 中讲师池晓东整理&#xff0c;整理于该活动中池老师所分享…

npm login报错:Public registration is not allowed

npm login报错:Public registration is not allowed 1.出现场景2.解决 1.出现场景 npm login登录时,出现 2.解决 将自己的npm镜像源改为npm的https://registry.npmjs.org/这个&#xff0c;解决&#xff01;

Android Studio 显示前进后退按钮

在写代码的过程中我们经常需要快速定位到先前或者往后的代码位置&#xff0c;可以使用Alt左右箭头 但是新安装的Android Studio工具栏上是没有显示左右箭头的工具按钮的&#xff0c;需要我们设置将Toolbar显示出来 View-Appearance-Toolbar 勾选即可 显示后

关于反射机制的简单理解

1、反射的简单认识 1.1 定义 Java的反射&#xff08;reflection&#xff09;机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意方法和属性&#xff0c;既然能拿到,那么我…

el-form与el-upload结合上传带附件的表单数据(后端篇)

1.写在之前 本文采用Spring Boot MinIO MySQLMybatis Plus技术栈&#xff0c;参考ruoyi-vue-pro项目。 前端实现请看本篇文章el-form与el-upload结合上传带附件的表单数据&#xff08;前端篇&#xff09;-CSDN博客。 2.需求描述 在OA办公系统中&#xff0c;流程表单申请人…