1.概述
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
2.结构
3.详解
栈是一种后进先出的结构,就如同水桶一般,从上往下接水,就叫做入栈,先接的水,就是先入栈的水在最下面,而出栈就是往外面倒水,先倒出的是最后进入的水,也就是最后入栈的数据,所以叫后进先出(LIFO)。
在最上面的叫做栈顶,我们一般使用的栈为顺序栈,底层使用的是数组,数组一开始就定义了大小,所以栈的大小也就早早定义了,数组尾被称为栈顶,数组开始的位置被称为栈底。实际的结构如下。
在栈结构中,是一种单向结构,所有的新增删除都只能从栈顶操作,新增时,从栈顶开始新增,删除也是先删除栈顶的元素,后添加的元素最先删除。
4.实际应用
在我们学习java的过程中,无可厚非的会接触到jvm的模型,我们可以知道在jvm中有操作数栈和堆,jvm的操作数栈便是栈的实际应用之一。那我们为什么在jvm中要使用操作数栈呢,看栈以下的优缺点
优点:
- 1.存取速度非常快,仅次于程序计数器,比堆的速度快很多
- 2.数据结构简单,线性结构,底层可使用数组和链表实现,非常多样化。
- 3.不需要垃圾回收,依靠top指针可实现对原值的覆盖
缺点:
- 1.灵活性差,只能进行后进先出
- 2.空间大小确定,空间利用率较低。
5.java代码实现简单计算器
5.1 使用数组实现一个顺序栈
@Data
@ToString
class ArrayStack {
private int maxSize;//栈的大小
private Object[] stack;//数组,栈的底层任然的数组
private int top = -1; //栈底,初始为-1
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
stack=new Object[maxSize];
}
/**
* 判断栈是否为空
*/
public boolean isNull() {
if (top == -1) {
return true;
} else {
return false;
}
}
/**
* 判断栈满
*/
public boolean isMax() {
if (top == maxSize - 1) {
return true;
} else {
return false;
}
}
/**
* 入栈
*/
public void push(Object num) {
if (isMax()) {
System.out.println("栈满");
return;
} else {
top++;
stack[top] = num;
}
}
/**
* 出栈
*/
public Object pop() {
if (isNull()) {
System.out.println("栈空,无法出栈");
return null;
} else {
Object value= stack[top];
top--;
return value;
}
}
/**
* 遍历栈
*/
public void list() {
if (isNull()) {
System.out.println("栈空");
} else {
int temp = top;
for (int i = temp; i > -1; i--) {
System.out.println(stack[i]);
}
}
}
/**
* 获取栈顶元素
*/
public Object head() {
return stack[top];
}
/**
* 判断优先级
*
* @param oper
* @return
*/
public int priority(char oper) {
if (oper == '*' || oper == '/') {
return 1;
} else {
return 0;
}
}
/**
* 计算
*
* @param num1
* @param num2
* @param oper
* @return
*/
public int cel(int num1, int num2, char oper) {
int result = 0; //存放结果
switch (oper) {
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2;
break;
case '+':
result = num1 + num2;
break;
case '-':
result = num2 - num1;
break;
}
return result;
}
}
5.2 实现计算器功能
@Test
public void StackSter() {
ArrayStack numberStack = new ArrayStack(10);//操作数栈
ArrayStack operStack = new ArrayStack(10);//符号栈
String expression = "2+3*6-2";
int num1 =0;
int num2 =0;
char oper;
int res=0;
char[] chars = expression.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (isNumber(chars[i])) {
// 判断为数字入数字栈
if (!numberStack.isMax()){
numberStack.push(chars[i]);
}
} else {
if (operStack.isNull()) {
// 如操作数栈为空直接压入栈
operStack.push(chars[i]);
} else {
boolean blag;
if (operStack.priority(chars[i]) <= operStack.priority((Character) operStack.head())) {
num1 = Integer.parseInt(String.valueOf(numberStack.pop()));
num2 = Integer.parseInt(String.valueOf(numberStack.pop()));
oper = (char) operStack.pop();
res = numberStack.cel(num1, num2, oper);
numberStack.push(res);
operStack.push(chars[i]);
}else {
operStack.push(chars[i]);
}
}
}
}
//表达式遍历完毕后,则按顺序从数栈和符号栈中pop出值进行运算
while (true) {
if (operStack.isNull()) {
break;
}
num1 = Integer.parseInt(String.valueOf(numberStack.pop()));
num2 = Integer.parseInt(String.valueOf(numberStack.pop()));
oper = (char) operStack.pop();
res = numberStack.cel(num1, num2, oper);
numberStack.push(res);
}
System.out.printf("表达式%s的结果为:%d", expression, numberStack.pop());
}
/**
* 判断是数字还是符号
*/
public static boolean isNumber(char c) {
if (c == '*' || c == '/' || c == '-' || c == '+') {
return false;
} else {
return true;
}
}