【数据结构(四)】栈(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、抗混叠方…...
收藏!小白程序员必看:AI赋能企业,从入门到精通的完整指南
本文深入浅出地介绍了人工智能(AI)的基本概念、发展历程及现状,特别是大模型的崛起及其划时代意义。文章重点阐述了AI如何赋能实体产业,通过具体案例展示了AI在智能家居、电网、床垫等行业的实际应用,强调AI与传统企业…...
Cowabunga Lite终极指南:5大功能让你无需越狱实现iOS深度个性化定制
Cowabunga Lite终极指南:5大功能让你无需越狱实现iOS深度个性化定制 【免费下载链接】CowabungaLite iOS 15 Customization Toolbox 项目地址: https://gitcode.com/gh_mirrors/co/CowabungaLite 厌倦了千篇一律的iOS界面?想个性化你的iPhone但又…...
Taotoken按Token计费模式解析,如何预估与控制API成本
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken按Token计费模式解析,如何预估与控制API成本 应用场景类,针对个人开发者与小团队关心的成本问题&a…...
GanttProject终极指南:免费开源项目管理工具完整教程
GanttProject终极指南:免费开源项目管理工具完整教程 【免费下载链接】ganttproject Official GanttProject repository. 项目地址: https://gitcode.com/gh_mirrors/ga/ganttproject GanttProject是一款功能强大的免费开源项目管理软件,专注于甘…...
从深度图到3D点云:用奥比中光摄像头和OpenNI玩转Python三维视觉(实战项目)
从深度图到3D点云:用奥比中光摄像头和OpenNI玩转Python三维视觉 当RGBD摄像头捕捉到的深度数据在屏幕上跳动时,那些数字背后隐藏着一个完整的三维世界。想象一下,你不仅能"看到"物体的平面图像,还能精确感知每个像素点…...
Diablo Edit2终极指南:5个简单步骤掌握暗黑破坏神II角色编辑器
Diablo Edit2终极指南:5个简单步骤掌握暗黑破坏神II角色编辑器 【免费下载链接】diablo_edit Diablo II Character editor. 项目地址: https://gitcode.com/gh_mirrors/di/diablo_edit Diablo Edit2是一款功能强大的暗黑破坏神II角色存档编辑器,专…...
Java 求职者面试:电商场景下的技术问答
面试官与燕双非:在电商场景下的 Java 技术问答 在一间面试室里,面试官严肃的坐在桌子后面,候选人燕双非在他的对面。面试官开始了一轮轮的技术问答,试图考察燕双非在 Java 和电商架构方面的能力。第一轮提问 面试官:燕…...
别再手动复制粘贴了!用Java的XWPFTemplate 1.9.1动态生成Word表格,5分钟搞定周报
告别手工周报:用JavaXWPFTemplate实现智能表格生成 每周五下午,办公室里总会响起此起彼伏的键盘敲击声和鼠标点击声——这是同事们正在与Word文档搏斗,手动复制粘贴数据、调整表格格式、核对数字准确性。这种重复性劳动不仅消耗时间ÿ…...
在自动化工作流中集成Taotoken实现多模型智能决策
在自动化工作流中集成Taotoken实现多模型智能决策 构建复杂的AI Agent或自动化流程时,单一模型的能力边界往往成为瓶颈。面对多样化的任务类型,开发者需要一种灵活、统一的方式来调度不同的模型资源。Taotoken作为大模型聚合分发平台,其Open…...
Bevy引擎光标交互解决方案:bevy_cursor库核心原理与实战应用
1. 项目概述:一个为Bevy游戏引擎量身定制的光标交互解决方案如果你正在用Bevy引擎开发游戏或交互式应用,并且被光标(鼠标)交互的逻辑搞得有点头疼,那么tguichaoua/bevy_cursor这个开源库很可能就是你正在寻找的“瑞士军…...
