栈的介绍
1,基础概念
- 栈的英文为(stack)
- 栈是一个先入后出(FILO-First In Last Out)的有序列表。
- 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
- 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
2,出栈(pop)示意图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9IzYJdRv-1652110264389)(D:\java\2022\2022年笔记\图片\图片1.png)]
3,入栈(push)示意图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vbCF0rkW-1652110264394)(D:\java\2022\2022年笔记\图片\图片2.png)]
4,栈的应用场景
- 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
- 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
- 表达式的转换[中缀表达式转后缀表达式]与求值(实际解决)。
- 二叉树的遍历。
- 图形的深度优先(depth一first)搜索法。
- 等到
5,数组模拟栈的基本操作
1,菜单测试数组模拟栈
public class ArrayStackTest {
public static void main(String[] args) {
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 values = scanner.nextInt();
stack.push(values);
break;
case "pop":
try {
int res = stack.pop();
System.out.println("出栈的数据为:" + res);
} catch (Exception ex) {
// TODO: 2022/4/27
System.out.println(ex.getMessage());
}
break;
case "exit":
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出!!!");
}
}
2,创建一个栈对象
class ArrayStack {
private int maxSize;
private int[] stack;
private int topSize = -1;
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
this.stack = new int[this.maxSize];
}
/**
* 判断栈是否已满
*
* @return
*/
public boolean isFull() {
return topSize == maxSize - 1;
}
/**
* 判断栈是否为空
*
* @return
*/
public boolean isEmpty() {
return topSize == -1;
}
/**
* 入栈操作
*
* @param value
*/
public void push(int value) {
if (isFull()) {
System.out.println("栈满!!");
return;
}
topSize++;
stack[topSize] = value;
}
/**
* 出栈操作
*
* @return
*/
public int pop() {
if (isEmpty()) {
System.out.println("空栈!!");
throw new RuntimeException("栈为空!");
}
int value = stack[topSize];
topSize--;
return value;
}
/**
* 栈的遍历
*/
public void list() {
if (isEmpty()) {
System.out.println("栈为空");
return;
}
for (int i = topSize; i >= 0; i--) {
System.out.println("栈中的数据为stact[i]="+stack[i]);
}
}
}
3,使用栈完成计算机逻辑
1,思路分析
使用栈完成表达式的计算 思路
1. 通过一个 index 值(索引),来遍历我们的表达式
2. 如果我们发现是一个数字, 就直接入数栈
3. 如果发现扫描到是一个符号, 就分如下情况
3.1 如果发现当前的符号栈为 空,就直接入栈
3.2 如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符, 就需要从数栈中pop出两个数,在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈, 如果当前的操作符的优先级大于栈中的操作符, 就直接入符号栈.
4. 当表达式扫描完毕,就顺序的从 数栈和符号栈中pop出相应的数和符号,并运行.
5. 最后在数栈只有一个数字,就是表达式的结果
验证: 5+2*6-2 = 13
2,代码实现
验证 String express = “5+2*6-2”
测试类入下:
public class ArrayStackTest01 { public static void main(String[] args) { //定义一个需要计算的表达式 String express = "30+2*6-2"; //创建两个栈,一个是数字的操作栈,一个是符号的操作栈 ArrayStack01 numStack = new ArrayStack01(10); ArrayStack01 operStack = new ArrayStack01(10); //定义一个辅助变量 int index = 0; int num1 = 0; int num2 = 0; int oper =0; int res = 0; char ch = ' '; while (true) { ch = express.substring(index, index + 1).charAt(0);//依次得到expression 的每一个字符 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); } //最后退出循环,判断是否扫描到表达式的最后 index++; if(index >= express.length()) { break; } } while (true) { //如果符号栈为空,则计算到最后结果,数栈中只有一个数子【结果】 if(operStack.isEmpty()) { break; } num1 = numStack.pop(); num2 = numStack.pop(); oper = operStack.pop(); res = numStack.cal(num1, num2, oper); numStack.push(res); } System.out.printf("表达式%s = %d", express, numStack.pop()); } }
创建一个栈对象,包括了一系列的方法
class ArrayStack01 { private int maxSize; private int[] stack; private int topSize = -1; public ArrayStack01(int maxSize) { this.maxSize = maxSize; this.stack = new int[this.maxSize]; } /** * 判断栈是否已满 * * @return */ public boolean isFull() { return topSize == maxSize - 1; } /** * 判断栈是否为空 * * @return */ public boolean isEmpty() { return topSize == -1; } /** * 入栈操作 * * @param value */ public void push(int value) { if (isFull()) { System.out.println("栈满!!"); return; } topSize++; stack[topSize] = value; } /** * 出栈操作 * * @return */ public int pop() { if (isEmpty()) { System.out.println("空栈!!"); throw new RuntimeException("栈为空!"); } int value = stack[topSize]; topSize--; return value; } /** * 栈的遍历 */ public void list() { if (isEmpty()) { System.out.println("栈为空"); return; } for (int i = topSize; i >= 0; i--) { System.out.println("栈中的数据为stact[i]=" + stack[i]); } } /** * 判断操作符的优先级 * @param oper * @return */ public int priority(int oper) { if(oper == '*' || oper == '/') { return 1; }else if(oper == '+' || oper == '-'){ return 0; }else { return -1; } } /** * 判断是否是+,-,*,/等操作 * @param val * @return */ public boolean isOper(char val) { return val == '+' || val == '-' || val == '*' || val == '/'; } /** * 两个数计算的方法 * @param num1 * @param num2 * @param oper * @return */ public int cal(int num1, int num2, int oper) { int res = 0; switch (oper) { case '+': res = num1 + num2; break; case '-': res = num2 - num1; break; case '*': res = num1 * num2; break; case '/': res = num2 / num1; break; default: break; } return res; } /** * 返回栈底的数,但是不是取出 * @return */ public int peek() { return stack[topSize]; } }