栈是什么
- 栈又名堆栈,是一种运算受限的线性表。仅限在表尾进行插入和删除操作的线性表,这一端被称为栈顶,而另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。百度百科
数组模拟栈
思想
- 定义一个top表示栈顶,初始化其值为-1
- 入栈,当有数据入栈时,top上移指向没有数据的位置
top++;
stack[top]=value;
- 出栈,输出栈顶元素,然后top指向下一个元素,下一个元素成为新的栈顶元素
int value=stack[top];
top--;
代码实现
public class ArrayStack {
private int maxSize;
private int[] stack;
private int top;
public ArrayStack(int maxSize) {
this.maxSize=maxSize;
stack=new int[this.maxSize];
this.top=-1;
}
public boolean isFull() {//判断栈是否满
return top==maxSize-1;
}
public boolean isEmpty() {//判断栈是否空
return top==-1;
}
public void push(int value) {
if(isFull()) {
System.out.printf("栈满,数据:%d\n",value);
return;
}
top++;
stack[top]=value;
}
public int pop() {
if(isEmpty()) {
throw new RuntimeException("栈为空,请先插入数据");
}
int value=stack[top];
top--;
return value;
}
public void show() {
if(isEmpty()) {
System.out.println("栈为空,请先插入数据");
return;
}
for(int i=top;i>=0;i--) {
System.out.printf("stack[%d]=%d\n",i,stack[i]);
}
}
public static void main(String[] args) {
ArrayStack as=new ArrayStack(4);
char key=' ';
Scanner scanner=new Scanner(System.in);
boolean loop=true;
while(loop) {
System.out.println("s(show)展示栈");
System.out.println("i(push)进栈");
System.out.println("o(pop)出栈一个数据");
System.out.println("e(exit)退出");
key=scanner.next().charAt(0);
switch(key) {
case 's':
as.show();
break;
case 'i':
System.out.println("请输入要插入的数据");
int value=scanner.nextInt();
as.push(value);
break;
case 'o':
as.pop();
break;
case 'e':
scanner.close();
loop=false;
break;
default:
break;
}
}
System.out.println("退出");
}
}
运行结果
s(show)展示栈
i(push)进栈
o(pop)出栈一个数据
e(exit)退出
i
请输入要插入的数据
1
s(show)展示栈
i(push)进栈
o(pop)出栈一个数据
e(exit)退出
i
请输入要插入的数据
2
s(show)展示栈
i(push)进栈
o(pop)出栈一个数据
e(exit)退出
s
stack[1]=2
stack[0]=1
s(show)展示栈
i(push)进栈
o(pop)出栈一个数据
e(exit)退出
o
s(show)展示栈
i(push)进栈
o(pop)出栈一个数据
e(exit)退出
s
stack[0]=1
s(show)展示栈
i(push)进栈
o(pop)出栈一个数据
e(exit)退出
o
s(show)展示栈
i(push)进栈
o(pop)出栈一个数据
e(exit)退出
s
栈为空,请先插入数据
s(show)展示栈
i(push)进栈
o(pop)出栈一个数据
e(exit)退出
e
退出
数组栈实现简单的四则运算的计算器(支持两位数)
- 实现该计算器需要两个栈,数栈用于存放数字,符号栈存放运算符。用的是中缀表达式。
- 为了实现该计算器,要在前面的栈的代码的基础上增加得到当前栈顶元素、返回优先级、判断字符是否为运算符和计算的方法
- 新增代码如下
public int showCyrrentTop() {//展示当前栈顶元素,不取出
return stack[top];
}
public int priority(int oper) {//判断运算符的优先级
if(oper=='*'||oper=='/') {
return 1;
}else if(oper=='*'||oper=='/') {
return 0;
}else return -1;
}
public boolean isOper(char value) {//判断字符是否为运算符
return value=='+'||value=='-'||value=='*'||value=='/';
}
public int calculate(int num1,int num2,int oper) {//运算
int result=0;
switch (oper) {
case '+':
result=num2+num1;
break;
case '-':
result=num2-num1;
break;
case '*':
result=num2*num1;
break;
case '/':
result=num2/num1;
break;
default:
break;
}
return result;
}
这里的priority方法放置的参数类型是int,但是可以传入char类型的变量,具体为什么详见具体原因
思想
- 设置一个变量index来遍历表达式
- 如果扫描到的是数字就入数栈
- 如果发现扫描到的是一个运算符,分2种情况的情况
- 情况1:当前符号栈为空,则该运算符直接入栈
- 情况2:当前符号栈不为空,就和当前栈顶元素的符号进行优先级比较,如果希望入栈的运算符优先级小于或等于栈顶元素的符号的优先级,则需要先从数栈中取出2个数字以及栈顶元素的符号进行运算,运算得到的数据再存储入数栈中,再将希望入栈的运算符入栈。反之,如果希望入栈的运算符的优先级大于栈顶元素的符号的优先级,就直接将希望入栈的运算符入栈。
- 表达式扫描完毕后,就将数栈和符号栈中的数据和运算符取出并求出结果。
- 最后只有数栈存在一个数据,这个数据就是表达式的结果。
代码实现
public class Calculator {
public static void simpleCaculator(String expression) {
ArrayStack numStack=new ArrayStack(10);//数栈
ArrayStack operStack=new ArrayStack(10);//运算符栈
int num1=0;
int num2=0;
int result=0;//num1、num2和result用于临时存放数据
int oper=0;
char index=' ';//用于遍历表达式
String keepNum="";//用于拼接数字
for(int i=0;i<expression.length();i++) {
index=expression.substring(i, i+1).charAt(0);
//一次取得表达式中的一个字符
if (!operStack.isOper(index)) {// 如果不是运算符
keepNum += index;
if (i == (expression.length() - 1)) {// 判断是否是最后一位
numStack.push(Integer.parseInt(keepNum));
} else {
// 查看当前位置的下一个位置的数据是不是数字,不是就将拼接的数字入栈
if (operStack.isOper(expression.substring(i + 1, i + 2).charAt(0))) {
numStack.push(Integer.parseInt(keepNum));// 让拼接的数字入栈
keepNum = "";//拼接好的数字入完栈以后,keepNum重新置为"",以便下次别的数字使用
}
}
}else {//如果是运算符
if(operStack.isEmpty()) {//如果运算符栈为空
operStack.push(index);
}else {//不为空
if(operStack.priority(index)<=operStack.priority(operStack.showCyrrentTop())) {
//如果优先级小于等于当前符号栈栈顶的优先级,就取出当前栈顶元素
//并取出数栈内的最靠近栈顶的2个数,进行运算
num1=numStack.pop();
num2=numStack.pop();
oper=operStack.pop();
result=numStack.calculate(num1, num2, oper);
numStack.push(result);
//运算完后,将结果插入数据栈
operStack.push(index);
//此时,再将希望入栈的运算符入栈
}else {//如果优先级大于符号栈当前栈顶元素的优先级就直接插入
operStack.push(index);
}
}
}
}
while(true) {
if(operStack.isEmpty()) {//当符号栈为空则说明运算完毕,跳出循环
break;
}
num1=numStack.pop();
num2=numStack.pop();
oper=operStack.pop();
result=numStack.calculate(num1, num2, oper);
numStack.push(result);
}
System.out.println(numStack.pop());
}
public static void main(String[] args) {
simpleCaculator("2+3*4-6");
simpleCaculator("20+30*40-60");
}
}
运行结果
8
1160