【数据结构】栈和队列的模拟实现

news2024/11/18 7:30:18

前言:前面我们学习了单链表并且模拟了它的实现,今天我们来进一步学习,来学习栈和队列吧!一起加油各位,后面的路只会越来越难走需要我们一步一个脚印!

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:数据结构 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


什么是栈

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出的原则(如下图所示)。
在这里插入图片描述
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。


如何实现栈

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。所以我们今天通过使用动态数组来模拟实现栈。


栈的基本结构

我们已经确定了通过动态数组来模拟实现栈,那么我们要实现哪些功能呢?

  1. 栈的初始化
  2. 栈的销毁
  3. 入栈
  4. 出栈
  5. 获取栈顶元素
  6. 检测栈是否为空
  7. 获取栈中有效元素个数

首先我们需要考虑如何记录栈顶元素的位置,我们用top来记录,但是top是不是应该是0还是什么数据呢?如果top指向的是0那么我top是0的时候栈中到底是一个元素还是没有元素,这是十分具有歧义的,所以我们这里用负一来表示top当有元素进入时就让top加加即可(如下图)。
在这里插入图片描述

具体结构如下:

typedef struct Stack
{
	STDataType* a;
	int top; //标识顶部
	int capacity;
}ST;

栈的基本功能

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top; //标识顶部
	int capacity;
}ST;

//栈的初始化
void STInit(ST* pst);

//栈的销毁
void STDestroy(ST* pst);

//栈顶插入删除

//入栈
void STPush(ST* pst, STDataType x);

//出栈
void STPop(ST* pst);

// 获取栈顶元素
STDataType STTop(ST* pst);

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool STEmpty(ST* pst);

// 获取栈中有效元素个数
int STSize(ST* pst);


栈的初始化

思路导读:前面我们讲到过用top来记录栈顶的位置,之所以让它从负一开始就是为了方便我们访问栈顶数据,也是为了防止歧义,如下图所示。我们初始化也只需要将开辟的空间指向空指针,空间容量为0即可。在这里插入图片描述代码实现:

void STInit(ST* pst)//栈的初始化
{
	assert(pst);
	pst->top = -1;//表示top指向栈顶元素的下一个位置
	pst->a = NULL;
	pst->capacity = 0;
}

栈的销毁

思路导读:我们只需要找到a开辟的空间将它释放掉并将他置为空指针即可,然后其它值Top处理为-1,空间容量置为0即可
代码实现

void STDestroy(ST* pst)//栈的销毁
{

	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = -1;
	pst->capacity = 0;
}


入栈

思路导读:我们入栈首先就是得开辟一块空间存放即将要入栈的值,然后将这块空间传给a即可,然后再把栈顶元素赋值,即可完成入栈。(如果这块地方有不懂的友友可以去看我之前的博客有详细讲解动态顺序表)
代码实现:

void STPush(ST* pst, STDataType x)//入栈
{
	assert(pst);
	if (pst->top + 1 == pst->capacity)//判断是否有空间
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);//防止开辟失败俩个空间都丢失
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->top++;//top加一
	pst->a[pst->top] = x;//栈顶赋值
}

出栈

思路导读:关于出栈,我们要知道他是先进后出,在前面的图中我们都有详细的讲解,出去一个元素我们让top往下走一个即可。
代码实现

void STPop(ST* pst)//出栈
{
	assert(pst);//判断是不是空
	assert(pst->top >= 0);//判断有没有元素
	pst->top--;//top减减即可
}

获取栈顶元素

思路导读:首先我们还是得判断传来的数据是否为空,里面是否有元素,然后我们直接访问栈顶元素即可。

STDataType STTop(ST* pst)// 获取栈顶元素
{
	assert(pst);
	assert(pst->top >= 0);
	return pst->a[pst->top];
}

函数测试与效果图:

void Test2()
{
	ST sl;
	STInit(&sl);
	STPush(&sl, 0);
	printf("%d ", STTop(&sl));
	STPush(&sl, 9);
	printf("%d ", STTop(&sl));
	STPush(&sl, 2);
	printf("%d ", STTop(&sl));
	STPush(&sl, 2);
	printf("%d ", STTop(&sl));
	printf("上面是入栈后\n");
	printf("下面是出栈后栈顶元素\n");
	STPop(&sl);
	printf("%d ", STTop(&sl));
	STPop(&sl);
	printf("%d ", STTop(&sl));
	STPop(&sl);
	printf("%d ", STTop(&sl));
	STPop(&sl);
}

在这里插入图片描述


检测栈是否为空

思路导读:首先判断传来的是否有这个结构体,我们只需要判断top是否是负一如果是说明这个为真则返回0,不是则返回非0的结果
代码实现:

bool STEmpty(ST* pst)// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
{
	assert(pst);
	return pst->top == -1;//如果是-1则是空返回true,如果不是返回false
}

获取栈中有效元素个数

思路导读:我们只需要将top加一即为元素个数,因为top指向的栈顶元素。

int STSize(ST* pst)// 获取栈中有效元素个数
{
	assert(pst);
	return pst->top + 1;
}

整体函数测试

void Test3()
{
	ST sl;
	STInit(&sl);
	STPush(&sl, 1);
	STPush(&sl, 3);
	STPush(&sl, 0);
	STPush(&sl, 9);
	STPush(&sl, 2);
	STPush(&sl, 8);
	printf("入栈后元素的个数:%d\n", STSize(&sl));
	printf("下面是入栈元素\n");
	while (!STEmpty(&sl))
	{	
		printf("%d ", STTop(&sl));
		STPop(&sl);//出栈
	}
	STDestroy(&sl);
}
int main()
{
	//Test1();
	//Test2();
	Test3();
	return 0;
}

具体效果图:
在这里插入图片描述
到这里关于栈的实现我们都已经讲完了,接下来我们开始队列的学习!


什么是队列

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出(我们可以通俗的理解成一头进一头出,先进去的先出去)。
入队列:进行插入操作的一端称为队尾。
出队列:进行删除操作的一端称为队头。
具体如下图
在这里插入图片描述


如何实现队列

由于队列的特殊性,只能一头进一头出,且先进的先出,在实现它的时候我们只需要考虑尾插和头删即可,在尾插和头删上效率较高的应该就是单链表了,但我们应当用一个tail的尾指针来记录,防止尾增的时候再次遍历链表。故我们通过单链表来实现队列。


队列的基本功能与结构

关于下面为什么会在用一个结构体来记录头指针和尾指针,是因为如果我们补定义一个结构体来记录,我们就会在入队列和出队列的时候,需要传一个二级指针来修改队列中的值,为了防止这样的麻烦我们就直接定义一个结构体来记录即可。


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 QueueDestory(Queue* pq);

// 队尾入队列
void QueuePush(Queue* pq, QDataType x);

// 队头出队列
void QueuePop(Queue* pq);

// 获取队列头部元素
QDataType QueueFront(Queue* pq);

// 获取队列队尾元素
QDataType QueueBack(Queue* pq);

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* pq);

// 获取队列中有效元素个数
int QueueSize(Queue* pq);

队列的初始化

思路导读:关于队列的初始化,我们只需要将头指针和尾指针置为空即可,然后将里面的元素置为0。
代码实现:

void QueueInit(Queue* pq)//队列的初始化
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

队尾入队列

思路导读:首先我们得分两种情况:一种是该队列为空第一次入队列,一种是该队列不为空不是第一次入队列,但无论如何都要开辟一块空间存放新开辟的值。当为第一次入队列的时候,我们只需要将头节点和尾节点全部指向这块新开辟的空间即可。当不是第一次入的时候,我们需要找到尾结点将它指向新开辟的这块空间即可完成入队列,且每当进入一个元素我们让size加加即可知道队列中的元素个数。如下图所示:
在这里插入图片描述
代码实现:

void QueuePush(Queue* pq, QDataType x)//队尾入队列
{
	assert(pq);
	QNode* newnode = 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);
	Queue* tmp = pq->phead;//记录头指针,方便释放空间
	pq->phead = pq->phead->next;//让头指针指向下一个元素
	free(tmp);//释放头指针
	if (pq->phead == NULL)//如果队列中只有一个元素,将尾指针也置为空指针
	{
		pq->ptail = NULL;
	}
	pq->size--;
}

获取队列头部元素

思路导读:我们只需要找到头节点指向的val的值将它返回即可。
代码实现

QDataType QueueFront(Queue* pq)// 获取队列头部元素
{
	assert(pq);
	assert(pq->phead);
	assert(pq->ptail);
	return pq->phead->val;
}


获取队列队尾元素

思路导读:我们在这之前一直记录了一个尾部节点,因此获取队尾元素的时候我们不需要重新在遍历队列,只需要返回尾节点的值即可。
代码实现

QDataType QueueBack(Queue* pq)// 获取队列队尾元素
{
	assert(pq);
	assert(pq->phead);
	assert(pq->ptail);
	return pq->ptail->val;
}


检测队列是否为空

思路导读:我们只需要判断之前存储数据个数的size是否为空即可。
代码实现

bool QueueEmpty(Queue* pq)// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
{
	assert(pq);
	return pq->size == 0;
}

获取队列中有效元素个数

思路导读:我们直接返回记录元素个数的size即可获取队列中有效元素的个数。

int QueueSize(Queue* pq)// 获取队列中有效元素个数
{
	assert(pq);
	return pq->size;
}

销毁队列

思路导读:我们要把队列中的每一个结点都释放掉,我们需要一个指针dl记录头指针原本的位置,让头指针往后走遍历队列依次释放经过的位置,具体如下图
在这里插入图片描述
代码实现:

void QueueDestory(Queue* pq)//销毁队列
{
	assert(pq);
	Queue* dl = NULL;
	while (pq->phead)
	{
		dl = pq->phead;
		pq->phead = pq->phead->next;
		free(dl);
	}
	pq->ptail = NULL;
	pq->size = 0;
	pq->phead = NULL;
}

整体函数测试

void Test2()
{
	Queue s;
	QueueInit(&s);
	QueuePush(&s, 1);
	QueuePush(&s, 2);
	QueuePush(&s, 3);
	QueuePush(&s, 4);
	QueuePush(&s, 5);
	printf("%d ", QueueFront(&s));		
	printf("%d ", QueueBack(&s));
		
	printf("%d\n", QueueSize(&s));
		
	QueuePop(&s);
		
	QueuePop(&s);
		
	printf("%d ", QueueFront(&s));
		
	printf("%d\n", QueueSize(&s));
	if (!QueueEmpty(&s))
	{
		QueuePop(&s);
		printf("%d ", QueueFront(&s));
		printf("%d\n", QueueSize(&s));
	}
	
	printf("%d\n", QueueSize(&s));
	QueueDestory(&s);
}

int main()
{
	//Test1();
	Test2();
	return 0;
}

运行结果:在这里插入图片描述


整体代码

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.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 QueueDestory(Queue* pq);

// 队尾入队列
void QueuePush(Queue* pq, QDataType x);

// 队头出队列
void QueuePop(Queue* pq);

// 获取队列头部元素
QDataType QueueFront(Queue* pq);

// 获取队列队尾元素
QDataType QueueBack(Queue* pq);

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* pq);

// 获取队列中有效元素个数
int QueueSize(Queue* pq);
#include"Queen.h"

void QueueInit(Queue* pq)//队列的初始化
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}


void QueuePush(Queue* pq, QDataType x)//队尾入队列
{
	assert(pq);
	QNode* newnode = 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);
	Queue* tmp = pq->phead;//记录头指针,方便释放空间
	pq->phead = pq->phead->next;//让头指针指向下一个元素
	free(tmp);//释放头指针
	if (pq->phead == NULL)//如果队列中只有一个元素,将尾指针也置为空指针
	{
		pq->ptail = NULL;
	}
	pq->size--;
}


QDataType QueueFront(Queue* pq)// 获取队列头部元素
{
	assert(pq);
	assert(pq->phead);
	assert(pq->ptail);
	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)// 获取队列队尾元素
{
	assert(pq);
	assert(pq->phead);
	assert(pq->ptail);
	return pq->ptail->val;
}


bool QueueEmpty(Queue* pq)// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
{
	assert(pq);
	return pq->size == 0;
}


int QueueSize(Queue* pq)// 获取队列中有效元素个数
{
	assert(pq);
	return pq->size;
}

void QueueDestory(Queue* pq)//销毁队列
{
	assert(pq);
	Queue* dl = NULL;
	while (pq->phead)
	{
		dl = pq->phead;
		pq->phead = pq->phead->next;
		free(dl);
	}
	pq->ptail = NULL;
	pq->size = 0;
	pq->phead = NULL;
}

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queen.h"

void Test1()
{
	Queue sl;
	QueueInit(&sl);
	QueuePush(&sl, 1);
	//printf("%d\n", QueueFront(&sl));
	QueuePush(&sl, 9);
	//printf("%d\n",QueueFront(&sl));
	//QueuePop(&sl);
	QueuePush(&sl, 2);
	QueuePush(&sl, 10);
	printf("%d\n", QueueFront(&sl));
	printf("%d\n",QueueBack(&sl));
}

void Test2()
{
	Queue s;
	QueueInit(&s);
	QueuePush(&s, 1);
	QueuePush(&s, 2);
	QueuePush(&s, 3);
	QueuePush(&s, 4);
	QueuePush(&s, 5);
	printf("%d ", QueueFront(&s));		
	printf("%d ", QueueBack(&s));
		
	printf("%d\n", QueueSize(&s));
		
	QueuePop(&s);
		
	QueuePop(&s);
		
	printf("%d ", QueueFront(&s));
		
	printf("%d\n", QueueSize(&s));
	if (!QueueEmpty(&s))
	{
		QueuePop(&s);
		printf("%d ", QueueFront(&s));
		printf("%d\n", QueueSize(&s));
	}
	
	printf("%d\n", QueueSize(&s));
	QueueDestory(&s);
}

int main()
{
	//Test1();
	Test2();
	return 0;
}

结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


🫵🫵🫵 祝各位接下来好运连连 💞

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

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

相关文章

提升--09-1--AQS底层逻辑实现

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、怎么解释AQS是什么&#xff1f;AQS的本质是JUC包下一个抽象类&#xff0c;AbstractQueuedSynchronizer &#xff08;抽象的队列式同步器&#xff09; 二、AQS核…

基于霍克斯过程的限价订单簿模型下的深度强化学习做市策略

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

【secureCRT连接Virtual Box里安装的Utuntu】

先说一下为什么要写这篇文章及一些背景问题介绍&#xff0c;楼主第一次使用secureCRT及securtFX这两个软件&#xff0c;在windows系统下访问虚拟机里面的ubuntu系统。看了网上的不少帖子&#xff0c;没有让我清晰明白地知道怎么使用secureCRT。连接不通&#xff0c;不知道是虚拟…

【Python】给出一个包含n个整数的数列,问整数a在数列中的第一次出现是第几个。

问题描述 给出一个包含n个整数的数列&#xff0c;问整数a在数列中的第一次出现是第几个。 输入格式 第一行包含一个整数n。 第二行包含n个非负整数&#xff0c;为给定的数列&#xff0c;数列中的每个数都不大于10000。 第三行包含一个整数a&#xff0c;为待查找的数。 输出格式…

LangChain的函数,工具和代理(一):OpenAI的函数调用

一、什么是函数调用功能 几个月前OpenAI官方发布了其API的函数调用功能(Function calling), 在 API 调用中&#xff0c;您可以描述函数&#xff0c;并让模型智能地选择输出包含调用一个或多个函数的参数的 JSON 对象。API函数“ChatCompletion” 虽然不会实际调用该函数&#…

redis之数据类型

&#xff08;一&#xff09;关系型数据库和非关系型数据库的区别 1、关系型数据库是一个机构化的数据库&#xff0c;列和行 &#xff08;1&#xff09;列&#xff1a;声明对象 &#xff08;2&#xff09;行&#xff1a;记录对象的属性 &#xff08;3&#xff09;表与表之间…

Python (十三) 输出

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一波电子书籍资料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虚拟机》&#xff0c;《重构改善既有代码设计》&#xff0c;《MySQL高性能-第3版》&…

使用pytorch利用神经网络原理进行图片的训练(持续学习中....)

1.做这件事的目的 语言只是工具,使用python训练图片数据,最终会得到.pth的训练文件,java有使用这个文件进行图片识别的工具,顺便整合,我觉得Neo4J正确率太低了,草莓都能识别成为苹果,而且速度慢,不能持续识别视频帧 2.什么是神经网络?(其实就是数学的排列组合最终得到统计结果…

Vue项目 配置项设置

一、项目运行时浏览器自动打开 找到package.json文件 找到"sctipts"配置项 在"serve"配置项最后加上--open "scripts": {"serve": "vue-cli-service serve --open","build": "vue-cli-service build&quo…

2023年【四川省安全员A证】复审考试及四川省安全员A证考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 四川省安全员A证复审考试根据新四川省安全员A证考试大纲要求&#xff0c;安全生产模拟考试一点通将四川省安全员A证模拟考试试题进行汇编&#xff0c;组成一套四川省安全员A证全真模拟考试试题&#xff0c;学员可通过…

Nacos介绍与使用

Nacos介绍与使用 文章目录 Nacos介绍与使用一. 什么是Nacos1 Nacos功能1.1 配置中心1.2 注册中心 2.为什么要使用Nacos 二.Nacos 部署安装1. Nacos 部署方式2. Nacos 安装3. 配置数据源4. 开启控制台授权登录&#xff08;可选&#xff09; 三. Nacos配置中心的使用1. 创建配置信…

2023/11/21JAVAweb学习

优先级高低id > 类 > 元素 格式化ctrl alt L

LeetCode热题100——动态规划

动态规划 1. 爬楼梯2. 杨辉三角3. 打家劫舍 1. 爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; // 题解&#xff1a;每次都有两种选择&#xff0c;1或者2 int climbStairs(int n) {if (n …

GAMES101—Lec 05~06:光栅化

目录 概念回顾&#xff08;个人理解&#xff09;光栅化1.采样2.采样出现的问题&#xff1a;走样 反走样 概念回顾&#xff08;个人理解&#xff09; 屏幕&#xff1a;在图形学中&#xff0c;我们认为屏幕是一个二维数组&#xff0c;数组里的每一个元素为一个二维像素。 光栅化…

【C++进阶之路】第四篇:set和map

文章目录 一、关联式容器健值对二、set & multiset三、map & multimap在这里插入图片描述 四、set和map底层原理 一、关联式容器健值对 关联式容器 & 键值对 二、set & multiset set & multiset 三、map & multimap map & multimap 四、set和…

【AT模式连接ONENET】ONENET可视化平台的使用

02 ONENET可视化平台的使用 ATCWMODE1 设置模式 ATCWDHCP1,1 启动DHCP功能 ①ATCWJAP"ssid","password" ATCWJAP“123456789”&#xff0c;“wang020118” ②ATMQTTUSERCFG0,1,"设备名字","设备ID","你的鉴权信息""…

JAVA项目测试----用户管理系统

一)项目简介: 用户管理系统是依据于前后端分离来实现的&#xff0c;是基于Spring SpringBoot Spring MVC&#xff0c;SpringAOP&#xff0c;MyBatis等框架来实现的一个用户管理网站&#xff0c;并且已经部署到了云服务器上, 目前的用户管理系统实现了超级管理员的注册功能&…

模电 01

一.半导体基本知识 1.优点&#xff1a;体积小、重量轻、使用寿命长、输入功率小、功率转换效率高。 2.性能介于导体与绝缘体 3.常用半导体材料&#xff1a;硅&#xff08;SI&#xff09; 镉&#xff08;Ge&#xff09;,化合物半导体&#xff1a;砷化镓&#xff08;GaAs&…

【封装UI组件库系列】全局样式的定义与重置

封装UI组件库系列第二篇样式​​​​​​​ ​​​​​​&#x1f31f;前言 &#x1f31f;定义全局样式 生成主题色和不同亮度的颜色 ​编辑 中性色及其他变量 &#x1f31f;样式重置 &#x1f31f;总结 ​​​​​​​​​​​​​​&#x1f31f;前言 在前端开发中&…