【数据结构(四)】栈(1)
文章目录
- 1. 关于栈的一个实际应用
- 2. 栈的介绍
- 3. 栈的应用场景
- 4. 栈的简单应用
- 4.1. 思路分析
- 4.2. 代码实现
- 5. 栈的进阶应用(实现综合计算器)
- 5.1. 栈实现一位数计算(中缀表达式)
- 5.1.1. 思路分析
- 5.1.2. 代码实现
- 5.2. 栈实现多位数计算(中缀表达式)
- 5.2.1. 解决思路
- 5.2.2. 代码实现:
1. 关于栈的一个实际应用
设计一个简单的计算器:
输入一个表达式,点击计算得出结果。
如:计算式:[7 * 2 * 2 - 5 + 1 - 5 + 3 - 3] 点击计算【如下图】

请问:
计算机底层是如何运算得到结果的? 注意不是简单的把算式列出运算, 而是计算机怎么理解这个算式的(对计算机而言,它接收到的就是一个字符串),我们讨论的是这个问题。–> 栈
2. 栈的介绍
- 栈(stack)是一个先入后出(FILO-First In Last Out)的有序列表。
- 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。(允许插入和删除的)一端为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
- 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
图解方式说明出栈(pop)和入栈(push)的概念

3. 栈的应用场景
- 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
- 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
- 表达式的转换[中缀表达式 转 后缀表达式]与求值(实际解决)。
- 二叉树的遍历。
- 图形的深度优先(depth 一 first)搜索法。
4. 栈的简单应用
问题:
用数组模拟栈的使用,由于栈是一种有序列表,当然可以使用数组的结构来储存栈的数据内容,下面我们就用数组模拟栈的出栈,入栈等操作。
4.1. 思路分析
思路分析:(使用数组来模拟栈)

①定义一个 top 来表示栈顶,初始化 为 -1
②入栈的操作,当有数据加入到栈时, top++; stack[top] = data;
③出栈的操作, int value = stack[top]; top--, return value
4.2. 代码实现
package stack;import java.util.Scanner;public class ArrayStackDemo {public static void main(String[] args) {// 创建一个ArrayStack对象-->表示栈ArrayStack stack = new ArrayStack(4);String key = "";boolean loop = true;// 控制是否退出菜单Scanner scanner = new Scanner(System.in);while (loop) {System.out.println("show: 表示显示栈");System.out.println("exit: 退出程序");System.out.println("push: 表示添加数据到栈(入栈)");System.out.println("pop: 表示从栈取出数据(出栈)");System.out.println("请输入你的选择");key = scanner.next();switch (key) {case "show":stack.list();break;case "push":System.out.println("请输入一个数");int value = scanner.nextInt();stack.push(value);break;case "pop":try {int res = stack.pop();System.out.printf("出栈的数据是 %d\n", res);} catch (Exception e) {// TODO: handle exceptionSystem.out.println(e.getMessage());}break;case "exit":scanner.close();loop = false;break;default:break;}}System.out.println("程序退出");}
}// 定义一个ArrayStck 表示栈
class ArrayStack {private int maxSize;// 栈的大小private int[] stack;// 数组,数组模拟栈:数据放在该数组private int top = -1;// top表示栈顶,初始化-1// 构造器public ArrayStack(int maxSize) {this.maxSize = maxSize;stack = new int[this.maxSize];}// 栈满public boolean isFull() {return top == maxSize - 1;}// 栈空public boolean isEmpty() {return top == -1;}// 入栈(push)public void push(int value) {// 先判断栈是否满if (isFull()) {System.out.println("栈满");return;}top++;stack[top] = value;}// 出栈(pop),将栈顶的数据返回public int pop() {// 先判断是否为空if (isEmpty()) {// 抛出异常throw new RuntimeException("栈空,没有数据");}int value = stack[top];top--;return value;}// 显示栈的情况(遍历栈):遍历时,需要从栈顶开始显示数据public void list() {if (isEmpty()) {System.out.println("栈空,没有数据");return;}for (int i = top; i >= 0; i--) {System.out.printf("stack[%d]=%d\n", i, stack[i]);}}}
运行结果:

习题拓展:
将上面的程序改成使用链表来模拟栈。
5. 栈的进阶应用(实现综合计算器)
5.1. 栈实现一位数计算(中缀表达式)
使用栈来实现综合计算器
问题:
请输入一个表达式,通过点击“点击计算”来输出计算结果
计算的表达式为:7 * 2 * 2 - 5 + 1 - 5 + 3 - 3
5.1.1. 思路分析
假设:
计算表达式为:3 + 2 * 6 - 2
计算思路:
1.通过一个 index 值(索引),来遍历我们的表达式
2.如果我们发现是一个数字, 就直接入数栈

3.如果发现扫描到是一个符号, 就分如下情况
3.1. 如果发现当前的符号栈为 空,就直接入栈

3.2. 如果符号栈有操作符,就进行比较
(1)如果当前的操作符的优先级小于或者等于栈中的操作符, 就需要从数栈中pop出两个数,在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈,;
(2)如果当前的操作符的优先级大于栈中的操作符, 就直接入符号栈。
因为计算表达式为:3 + 2 * 6 - 2
栈中已经存放了3和+,下一步该想数栈中存放2,直接入栈

接下来,扫描到符号 *
当前的操作符 * 的优先级大于栈中的操作符 + ,直接入符号栈

接下来,扫描到数字6,直接入数栈

接下来,扫描到符号 -
当前的操作符 - 的优先级小于(或等于)栈中的操作符 * ,直接入符号栈
需要从数栈中pop出两个数(6 和 2),在从符号栈中pop出一个符号(*),进行运算,将得到结果(12),入数栈
2 * 6 = 12

然后将当前的操作符( - )入符号栈。

接下来,扫描到数字2,直接入数栈

4.当表达式扫描完毕,就顺序的从 数栈和符号栈中pop出相应的数和符号,并运行
①12 - 2 = 10

②3 + 10 =13

5.最后在数栈只有一个数字,就是表达式的结果(即13)
5.1.2. 代码实现
package stack;public class Calculator {public static void main(String[] args) {// 给出一个计算表达式String expression = "3+2*6-2";// String expression = "7+2*6-4";// 创建两个栈:数栈 和 符号栈ArrayStack2 numStack = new ArrayStack2(10);ArrayStack2 operStack = new ArrayStack2(10);// 定义相关变量int index = 0;// 用于扫描int num1 = 0;int num2 = 0;int oper = 0;int res = 0;char ch = ' ';// 将每次扫描得到的char保存到ch// 使用while循环的扫描expressionwhile (true) {// 一次得到expression的每一个字符ch = expression.substring(index, index + 1).charAt(0);// 判断ch是什么,然后做相应的处理if (operStack.isOper(ch)) {// 如果是运算符// 判断当前的符号是否为空if (!operStack.isEmpty()) {// 如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符, 就需要从数栈中pop出两个数// 在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = numStack.cal(num1, num2, oper);// 把运算的结果入 数栈numStack.push(res);// 然后将当前的操作符入 符号栈operStack.push(ch);} else {// 如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈operStack.push(ch);}} else {// 如果为空直接入 符号栈operStack.push(ch);}} else {// 如果是数,直接入 数栈numStack.push(ch - 48);// ASCII码表对应数值要减去48}// 让index++,并判断是否扫描到expression最后index++;if (index >= expression.length()) {break;}}// 当表达式扫描完毕,就顺序的从 数栈和符号栈中pop出相应的数和符号,并运行while (true) {// 如果符号栈为空,就得到了最后的计算结果,数栈中只有一个数字(即运算结果)if (operStack.isEmpty()) {break;}num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = numStack.cal(num1, num2, oper);// 把运算的结果入 数栈numStack.push(res);}// 将数栈的最后的数。pop出,就是结果int res2 = numStack.pop();System.out.printf("表达式 %s = %d", expression, res2);}
}// 先创建一个栈
// 定义一个ArrayStck 表示栈
class ArrayStack2 {private int maxSize;// 栈的大小private int[] stack;// 数组,数组模拟栈:数据放在该数组private int top = -1;// top表示栈顶,初始化-1// 构造器public ArrayStack2(int maxSize) {this.maxSize = maxSize;stack = new int[this.maxSize];}// 增加一个方法,可以返回当前栈顶的值,但不是真正的poppublic int peek() {return stack[top];}// 栈满public boolean isFull() {return top == maxSize - 1;}// 栈空public boolean isEmpty() {return top == -1;}// 入栈(push)public void push(int value) {// 先判断栈是否满if (isFull()) {System.out.println("栈满");return;}top++;stack[top] = value;}// 出栈(pop),将栈顶的数据返回public int pop() {// 先判断是否为空if (isEmpty()) {// 抛出异常throw new RuntimeException("栈空,没有数据");}int value = stack[top];top--;return value;}// 显示栈的情况(遍历栈):遍历时,需要从栈顶开始显示数据public void list() {if (isEmpty()) {System.out.println("栈空,没有数据");return;}for (int i = top; i >= 0; i--) {System.out.printf("stack[%d]=%d\n", i, stack[i]);}}// 返回运算符的优先级,优先级是程序员来确定的,优先级使用数字表示// 数字越大,优先级就越高public int priority(int oper) {if (oper == '*' || oper == '/') {return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1;// 假定目前的表达式只有+,-,*,/}}// 判断是不是一个运算符public boolean isOper(char val) {return val == '+' || val == '-' || val == '*' || val == '/';}// 计算方法public int cal(int num1, int num2, int oper) {int res = 0;// 用于存放计算结果switch (oper) {case '+':res = num2 + num1;break;case '-':res = num2 - num1;break;case '*':res = num2 * num1;break;case '/':res = num2 / num1;break;default:break;}return res;}}
运行结果:

注意:
上述代码在计算多位数会出现问题(比如计算:30+2*6-2,会错误的计算成10)
因为在数据读取的时候,是一个字符一个字符的读取,这样就把30拆成了 3 和 0 ,因此计算出错。
5.2. 栈实现多位数计算(中缀表达式)
5.2.1. 解决思路
1.当处理多位数时,不能发现是一个数就立即入栈,因为它可能是多位数
2.在处理数时,需要向expression的表达式的index后再看一位,如果是多位数就进行扫描,如果是符号才入栈
3.因此我们需要定义一个变量 字符串,用于拼接
5.2.2. 代码实现:
package stack;public class Calculator {public static void main(String[] args) {// 给出一个计算表达式String expression = "30+2*6-2";// String expression = "7+2*6-4";// 创建两个栈:数栈 和 符号栈ArrayStack2 numStack = new ArrayStack2(10);ArrayStack2 operStack = new ArrayStack2(10);// 定义相关变量int index = 0;// 用于扫描int num1 = 0;int num2 = 0;int oper = 0;int res = 0;char ch = ' ';// 将每次扫描得到的char保存到chString keepNum = "";//用于拼接多位数// 使用while循环的扫描expressionwhile (true) {// 一次得到expression的每一个字符ch = expression.substring(index, index + 1).charAt(0);// 判断ch是什么,然后做相应的处理if (operStack.isOper(ch)) {// 如果是运算符// 判断当前的符号是否为空if (!operStack.isEmpty()) {// 如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符, 就需要从数栈中pop出两个数// 在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = numStack.cal(num1, num2, oper);// 把运算的结果入 数栈numStack.push(res);// 然后将当前的操作符入 符号栈operStack.push(ch);} else {// 如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈operStack.push(ch);}} else {// 如果为空直接入 符号栈operStack.push(ch);}} else {// 如果是数,直接入 数栈// numStack.push(ch - 48);// ASCII码表对应数值要减去48//分析思路//1. 当处理多位数时,不能发现是一个数就立即入栈,因为它可能是多位数//2.在处理数时,需要向expression的表达式的index后再看一位,如果是多位数就进行扫描,如果是符号才入栈//3.因此我们需要定义一个变量 字符串,用于拼接//处理多位数keepNum += ch;//如果ch已经是expression的最后一位,就直接入栈if (index == expression.length() - 1) {numStack.push(Integer.parseInt(keepNum));} else {// 判断下一个字符是不是数字,如果是数字就继续扫描,如果是运算符,则入栈// 注意:这里是看后一位,不是index++if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {// 如果后一位是运算符,则入栈(keepNum可能是 一位数,也可能是 多位数)numStack.push(Integer.parseInt(keepNum));// 注意:一定要清空keepNumkeepNum = "";}}}// 让index++,并判断是否扫描到expression最后index++;if (index >= expression.length()) {break;}}// 当表达式扫描完毕,就顺序的从 数栈和符号栈中pop出相应的数和符号,并运行while (true) {// 如果符号栈为空,就得到了最后的计算结果,数栈中只有一个数字(即运算结果)if (operStack.isEmpty()) {break;}num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = numStack.cal(num1, num2, oper);// 把运算的结果入 数栈numStack.push(res);}// 将数栈的最后的数。pop出,就是结果int res2 = numStack.pop();System.out.printf("表达式 %s = %d", expression, res2);}
}// 先创建一个栈
// 定义一个ArrayStck 表示栈
class ArrayStack2 {private int maxSize;// 栈的大小private int[] stack;// 数组,数组模拟栈:数据放在该数组private int top = -1;// top表示栈顶,初始化-1// 构造器public ArrayStack2(int maxSize) {this.maxSize = maxSize;stack = new int[this.maxSize];}// 增加一个方法,可以返回当前栈顶的值,但不是真正的poppublic int peek() {return stack[top];}// 栈满public boolean isFull() {return top == maxSize - 1;}// 栈空public boolean isEmpty() {return top == -1;}// 入栈(push)public void push(int value) {// 先判断栈是否满if (isFull()) {System.out.println("栈满");return;}top++;stack[top] = value;}// 出栈(pop),将栈顶的数据返回public int pop() {// 先判断是否为空if (isEmpty()) {// 抛出异常throw new RuntimeException("栈空,没有数据");}int value = stack[top];top--;return value;}// 显示栈的情况(遍历栈):遍历时,需要从栈顶开始显示数据public void list() {if (isEmpty()) {System.out.println("栈空,没有数据");return;}for (int i = top; i >= 0; i--) {System.out.printf("stack[%d]=%d\n", i, stack[i]);}}// 返回运算符的优先级,优先级是程序员来确定的,优先级使用数字表示// 数字越大,优先级就越高public int priority(int oper) {if (oper == '*' || oper == '/') {return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1;// 假定目前的表达式只有+,-,*,/}}// 判断是不是一个运算符public boolean isOper(char val) {return val == '+' || val == '-' || val == '*' || val == '/';}// 计算方法public int cal(int num1, int num2, int oper) {int res = 0;// 用于存放计算结果switch (oper) {case '+':res = num2 + num1;break;case '-':res = num2 - num1;break;case '*':res = num2 * num1;break;case '/':res = num2 / num1;break;default:break;}return res;}}
运行结果:

习题拓展:
对上述代码加入功能,能够实现含小括号表达式的运算。
相关文章:
【数据结构(四)】栈(1)
文章目录 1. 关于栈的一个实际应用2. 栈的介绍3. 栈的应用场景4. 栈的简单应用4.1. 思路分析4.2. 代码实现 5. 栈的进阶应用(实现综合计算器)5.1. 栈实现一位数计算(中缀表达式)5.1.1. 思路分析5.1.2. 代码实现 5.2. 栈实现多位数计算(中缀表达式)5.2.1. 解决思路5.2.2. 代码实…...
实验(四):指令部件实验
一、实验内容与目的 实验要求: 利用CP226实验仪上的小键盘将程序输入主存储器EM,通过指令的执行实现微程序控制器的程序控制。 实验目的: 1.掌握模型机的操作码测试过程; 2.掌握模型机微程序控制器的基本结构以及程序控制的基本原…...
【Android11】在内置的Tvsettings的界面中显示以太网Mac地址
【Android11】在内置的Tvsettings的界面中显示以太网Mac地址 了解Preference必要信息步骤:1. 在设置页面的xml文件中增加一个Preference ,这是要显示出来的设置项2. 在strings.xml文件中增加我们在第一步新设置的值3. 为新加的设置项增加一个新的XXXPref…...
在Oracle 11g 数据库上设置透明数据加密(TDE)
本文回答2个问题: 11g下简明的TDE设置过程由于11g不支持在线TDE,介绍2中11g下的加密表空间的迁移方法 设置表空间TDE之前 表空间没有加密时,很容易探测到明文数据: create tablespace unsectbs datafile unsectbs.dbf size 10…...
互动直播 之 视频帧原始数据管理
目录 一、视频帧管理 1、存储图片数据的数据结构 1.1)、图片数据首地址...
基于tcp协议及数据库sqlite3的云词典项目
这个小项目是一个网络编程学习过程中一个阶段性检测项目,过程中可以有效检测我们对于服务器客户端搭建的能力,以及一些bug查找能力。项目的一个简单讲解我发在了b站上,没啥心得,多练就好。 https://t.bilibili.com/86524470252640…...
C/C++内存管理(1):C/C++内存分布,C++内存管理方式
一、C/C内存分布 1.1 1.2 二、C内存管理方式 C可以通过操作符new和delete进行动态内存管理。 2.1 new和delete操作内置类型 int main() {int* p1 new int;// 注意区分p2和p3int* p2 new int(10);// 对*p2进行初始化 10int* p3 new int[10];// p3 指向一块40个字节的int类…...
11 redis中分布式锁的实现
单机锁代码 import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.con…...
循环链表3
插入函数——插入数据,在链表plsit的pos位置插入val数据元素 位置pos(在无特别说明的情况下)是从0开始计数的 要改变链表结构,就要依赖前驱,每个前驱的next存储着下一个数据结点的地址,也就是依靠前驱的ne…...
如何修改百科内容?百度百科内容怎么修改?
百科词条创建上去是相当不易的,同时修改也是如此,一般情况下,百科词条是不需要修改的,但是很多时候企业或是人物在近期收获了更多成就或是有更多的变动,这个时候就需要补充维护词条了,如何修改百科内容&…...
mysql8.0英文OCP考试第131-140题
Q131.You have upgraded the MySQL binaries from 5.7.28 to 8.0.18 by using an in-place upgrade. Examine the message sequence generated during the first start of MySQL 8.0.18: 。。。[System]。。。/usx/sbin/mysqld (mysqld 8.0.18-commercial) starting as proces…...
MySQL数据库——存储过程-条件处理程序(通过SQLSTATE指定具体的状态码,通过SQLSTATE的代码简写方式 NOT FOUND)
目录 介绍 案例 通过SQLSTATE指定具体的状态码 通过SQLSTATE的代码简写方式 NOT FOUND 介绍 条件处理程序(Handler)可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。具体语法为: DECLARE handler_action HANDLER FOR c…...
信号的处理时机(内核态,用户态,如何/为什么相互转换,内核空间,cpu寄存器),信号的处理流程详细介绍+抽象图解
目录 信号的处理时机 引入 思考 -- 什么时候才能算合适的时候呢? 用户态转为内核态 引入 内核地址空间 引入 思考 -- 进程为什么能切换成内核态呢? 虚拟地址空间 注意点 原理 (总结一下) 为什么如何进入内核态 引入 介绍 底层原理(int 80) cpu的寄存器 用…...
【JavaEE】Spring的创建和使用(保姆级手把手图解)
一、创建一个Spring项目 1.1 创建一个Maven项目 1.2 添加 Spring 框架支持 在pom.xml中添加 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE&…...
MyBatis:关联查询
MyBatis 前言关联查询附懒加载对象为集合时的关联查询 前言 在 MyBatis:配置文件 文章中,最后介绍了可以使用 select 标签的 resultMap 属性实现关联查询,下面简单示例 关联查询 首先,先创建 association_role 和 association_…...
第十二章 控制值的转换
文章目录 第十二章 控制值的转换介绍处理特殊 XML 字符文字和 SOAP 编码格式的转义形式 示例防止泄漏的另一种方法 第十二章 控制值的转换 类和属性参数 ESCAPE CONTENT XMLTIMEZONE DISPLAYLIST VALUELIST XMLDEFAULTVALUE XMLLISTPARAMETER XMLSTREAMMODE 介绍 支…...
SQL并集、交集、差集使用
一、概述 SQL语句实现数据的并集(union)、交集(intersect)、差集(except)。 二、案例 1、stu表 idname1张三2李四3王二 2、并集 union union 运算:表示取并集,例如:…...
【双指针】盛水最多的容器
盛水最多的容器 文章目录 盛水最多的容器题目描述算法原理思路一思路二 代码实现Java代码实现C代码实现 题目描述 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与…...
win11,引导项管理
1,打开cmd,输入msconfig 2,进入引导选项卡 3,删除不需要的引导项...
YoloV8改进策略:WaveletPool解决小目标的混叠问题,提高小目标的检测精度
文章目录 摘要论文:《抗混叠在微小目标检测中的重要性》1、简介2、相关研究2.1、微小物体检测2.2. 抗锯齿过滤器3、方法3.1. Wavelet Pooling3.2 一致顺序的Wavelet Pooling的WaveCNet3.3、Bottom-Heavy Backbone4、实验4.1、预训练数据集4.2、微小目标检测数据集4.3、抗混叠方…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...
