计算机计算表达式:[722-5+1-5+3-3] 的值?
请问:
计算机底层是如何运算得到结果的?
注意不是简单的把算式列出运- 算,因为我们看这个算式
7 * 2 * 2 -5
但是计算机怎么理解这个算式的 对计算机而言, 它接收到的就是一个字符串, 这个问题:栈
栈的应用场景与介绍
栈的基本性质
- 栈是一个先入后出(FILO-First In Last Out)的有序列表
- 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。
- 允许插入和删除的一端, 为变化的一端, 称为栈顶(Top), 另一端为固定的一端, 称为栈底(Bottom)。
- 根据栈的定义可知, 最先放入栈中元素在栈底, 最后放入的元素在栈顶, 而删除元素刚好相反, 最后放入的元素最先删除, 最先放入的元素最后删除也就是遵循先进后出规则
图解
栈的应用场景
- 子程序的调用: 在跳往子程序前, 会先将下个指令的地址存到堆栈中, 直到子程序执行完后再将地址取出, 以回到原来的程序中。
- 处理递归调用: 和子程序的调用类似, 只是除了储存下一个指令的地址外, 也将参数、 区域变量等数据存入栈中。
- 表达式的转换:[中缀表达式转后缀表达式]与求值(实际解决)。
二叉树的遍历。 - 图形的深度优先(depth 一 first)搜索法。
代码实现
//定义一个类表示栈结构
static class ArrayStack{
private int maxSize;//表示栈的大小
private int[] stack;//数组,数组模拟栈,数据就放在该数组中
private int top = -1;//top表示栈顶,初始化为-1
//构造器
public ArrayStack(int maxSize){
this.maxSize = maxSize;
stack = new int[maxSize];
}
//栈满
public boolean isFull(){
return top == maxSize - 1;
}
//栈空
public boolean isEmpty(){
return top == -1;
}
//入栈
public void push(int value){
if (isFull()){
System.out.println("栈满~~~");
}
top++;
stack[top] = value;
}
//出栈,将栈顶的数据返回
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]);
}
}
}
使用栈结构实现计算器
package com.ghl.stack;
/**
* @Date:2021/6/14
* @Author:GuoHeLong
*/
public class Calculator {
public static void main(String[] args) {
String expression = "3+2*6-2";
ArrayStack2 numberStack = new ArrayStack2(10);
ArrayStack2 operStack = new ArrayStack2(10);
//定义需要扫描的索引
int num1 = 0;
int num2 = 0;
int oper = 0;
int res = 0;
String keepNum = "";
char[] chars = expression.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (operStack.isOper(chars[i])) { //判断是否是运算符
if (!operStack.isEmpty()) {//判断当前操作栈是否为空
if (operStack.proority(chars[i]) <= operStack.proority(operStack.stack[operStack.top])) {//对比栈顶的运算级别
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = operStack.pop();
res = numberStack.cal(num1, num2, oper);
numberStack.push(res);
operStack.push(chars[i]);
} else {//如果栈顶为-,当前oper为*则直接存入压入栈中
operStack.push(chars[i]);
}
} else {//操作栈为空直接压入栈中
operStack.push(chars[i]);
}
} else { //是数字
// 1. 当处理多位数时,不能发现是一个数就立即入栈,因为他可能是多位数
keepNum += chars[i];
while (true) {
if (i == chars.length-1) {//当前数字已经是最后一位
break;
} else {
if (!operStack.isOper(chars[i+1])) { //判断后一位是不是运算符
keepNum += chars[i+1]; //拼装上后一位数字
i++;
} else {//下一位是运算符结束循环
break;
}
}
}
//向后查找完毕
numberStack.push(Integer.parseInt(keepNum));
keepNum = "";//keepNum使用后一定要清空,否则会保留之前的数据
}
}
numberStack.list();
// 当表达式扫描完毕,就顺序的从 数栈和符号栈中pop出相应的数和符号,并运行.
while (true) {
// 如果符号栈为空,则计算到最后的结果, 数栈中只有一个数字【结果】
if (operStack.isEmpty()) {
break;
}
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = operStack.pop();
res = numberStack.cal(num1, num2, oper);
numberStack.push(res);// 入栈
}
// 将数栈的最后数,pop出,就是结果
res = numberStack.pop();
System.out.printf("表达式 %s = %d", expression, res);
}
//定义一个类表示栈结构
static class ArrayStack2 {
private int maxSize;//表示栈的大小
private int[] stack;//数组,数组模拟栈,数据就放在该数组中
private int top = -1;//top表示栈顶,初始化为-1
//构造器
public ArrayStack2(int maxSize) {
this.maxSize = maxSize;
stack = new int[maxSize];
}
//栈满
public boolean isFull() {
return top == maxSize - 1;
}
//栈空
public boolean isEmpty() {
return top == -1;
}
//入栈
public void push(int value) {
if (isFull()) {
System.out.println("栈满~~~");
}
top++;
stack[top] = value;
}
//出栈,将栈顶的数据返回
public int pop() {
//先判断栈是否空
if (isEmpty()) {
throw new RuntimeException("栈空~~~");
}
int value = stack[top];
top--;
return value;
}
//显示栈的情况,遍历。需要从栈顶开始显示数据
public void list() {
System.out.println("==========遍历栈============");
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 proority(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;//res用于存放计算结果
switch (oper) {
case '+':
res = num1 + num2;
break;
case '-':
res = num2 - num1;
break;
case '*':
res = num1 * num2;
break;
default:
res = num2 / num1;
break;
}
return res;
}
}
}
逆波兰表达式的计算求值
- 后缀表达式==逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后
正常的表达式 | 逆波兰表达式 |
---|---|
a+b | a b + |
a+(b-c) | a b c - + |
a+(b-c)*d | a+(b-c)*d |
a+d*(b-c) | a d b c - * + |
a=1+3 | a 1 3 + = |