、
栈的介绍
- 栈的英文为(stack)
- 栈是一个先入后出(FILO-First In Last Out)的有序列表。
- 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的 一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
- 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元 素最先删除,最先放入的元素最后删除
- 图解方式说明出栈(pop)和入栈(push)的概念
栈的应用场景
1) 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以 回到原来的程序中。 2) 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆 栈中。 3) 表达式的转换 [ 中缀表达式转后缀表达式 ] 与求值 ( 实际解决 ) 。 4) 二叉树的遍历。 5) 图形的深度优先 (depth 一 first) 搜索法。栈的快速入门
1) 用数组模拟栈的使用,由于栈是一种有序列表,当然可以使用数组的结构来储存栈的数据内容, 下面我们就用数组模拟栈的出栈,入栈等操作。 2) 实现思路分析 , 并画出示意图数组模拟栈实现
class ArrayStack{
private int top = -1; //栈顶
private int[] arr; //模拟用的数组
private int maxSize; //最大容量
//初始化数组
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
}
/**
* 判断栈是否满
* @return
*/
public boolean isFull(){
return top == maxSize-1;
}
/**
* 判断栈空
*/
public boolean isEmpty(){
return top == -1;
}
/**
* 入栈
* @param num 新入栈的值
*/
public void push(int num){
if (isFull()) {
System.out.println("栈满");
return;
}
arr[++top] = num;
}
/**
* 出栈
* @return 返回栈顶数据
*/
public int pop(){
if (isEmpty()){
System.out.println("栈空");
return -1;
}
return arr[top--];
}
/**
* 查看栈顶
* @return
*/
public int peek(){
if (isEmpty()){
System.out.println("栈空");
return -1;
}
return arr[top];
}
/**
* 遍历栈 需要从栈顶开始遍历
*/
public void iteratorStack(){
if (isEmpty()){
System.out.println("栈空");
return;
}
for (int i = top; i > 0; i--) {
System.out.printf("%d\t",arr[i]);
}
}
}
使用栈实现一个计算器
思路:
package shangguigu2.栈;
public class Calaculator {
public static void main(String[] args) {
//根据前面的思路完成表达式计算
String expression = "301+2*6-2";
ArrayStack2 numsStack = new ArrayStack2(100); //数栈
ArrayStack2 oprStack = new ArrayStack2(100); //符号栈
//定义相关变量
int index = 0,num1 = 0,num2 = 0,oper = 0,res = 0;
char ch = ' '; //每次扫描得到的char就保存在这里
String keepNum = "";//用于拼接多位数
//开始扫描
while (true){
//依次得到每一个字符
ch = expression.substring(index,index+1).charAt(0);
//判断ch是什么,然后做相应处理
if (oprStack.isOpr(ch)){
//如果是符号,那再检查符号栈是不是空,如果为空直接入栈
if (!oprStack.isEmpty()){
//有操作符,进行比较优先级,如果当前符号的优先级小于或等于栈中的操作符
//就需要从数栈内pop两个数,符号栈pop一个符号来进行计算,得到结果入数栈。然后将当前的操作符入符号栈
//如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈
if(oprStack.priority(ch) <= oprStack.priority(oprStack.peek())){
//满足,从数栈pop两个数进行操作
num1 = numsStack.pop();
num2 = numsStack.pop();
oper = oprStack.pop();
res = numsStack.cal(num1,num2,oper);
numsStack.push(res);
//最后再把当前符号push到符号栈
oprStack.push(ch);
}else {
//如果当前符号优先级较大,那就直接入符号栈
oprStack.push(ch);
}
}else {
//为空直接入栈
oprStack.push(ch);
}
}else {//如果是数字的处理
//numsStack.push(ch - 48); //-48是因为1对应的是ASC码表
//当处理多位数时,不能发现一个数就立即入栈,要考虑多位数的情况。
//在处理数时需要多扫描几下,直到扫到符号,以便处理多位数
//因此需要定义一个字符串变量用来拼接多位数。
//处理多位数
keepNum+=ch;
//如果已经是表达式最后一位了,那就直接入栈
if (index == expression.length()-1){
numsStack.push(Integer.parseInt(keepNum));
}else {
//判断下一个字符是不是数字 如果是数字则继续扫描,如果是符合则入栈
if (oprStack.isOpr(expression.substring(index+1,index+2).charAt(0))){ //向后探一位
//如果是运算符则入栈
numsStack.push(Integer.parseInt(keepNum));
//清空keepNum
keepNum = "";
}
}
}
index++;
if (index >= expression.length()){
break;
}
}
//当表达式扫描完毕,就顺序的从数栈和符号栈内pop出相应的数和符号,并运行
while (true){
//如果符号栈为空则计算结束了,数栈中只有一个结果了
if (oprStack.isEmpty()){
break;
}
num1 = numsStack.pop();
num2 = numsStack.pop();
oper = oprStack.pop();
res = numsStack.cal(num1,num2,oper);
numsStack.push(res);
}
System.out.println("表达式:"+expression+"="+numsStack.pop());
}
}
class ArrayStack2{
private int top = -1; //栈顶
private int[] arr; //模拟用的数组
private int maxSize; //最大容量
//初始化数组
public ArrayStack2(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
}
/**
* 判断栈是否满
* @return
*/
public boolean isFull(){
return top == maxSize-1;
}
/**
* 判断栈空
*/
public boolean isEmpty(){
return top == -1;
}
/**
* 入栈
* @param num 新入栈的值
*/
public void push(int num){
if (isFull()) {
System.out.println("栈满");
return;
}
arr[++top] = num;
}
/**
* 出栈
* @return 返回栈顶数据
*/
public int pop(){
if (isEmpty()){
System.out.println("栈空");
return -1;
}
return arr[top--];
}
/**
* 查看栈顶
* @return
*/
public int peek(){
if (isEmpty()){
System.out.println("栈空");
return -1;
}
return arr[top];
}
/**
* 遍历栈 需要从栈顶开始遍历
*/
public void iteratorStack(){
if (isEmpty()){
System.out.println("栈空");
return;
}
for (int i = top; i > 0; i--) {
System.out.printf("%d\t",arr[i]);
}
}
/**
* 返回运算符的优先级 优先级由程序员确定,数字越大优先级越高
*/
public int priority(int opr){
if (opr == '*' || opr == '/'){
return 1;
}else if (opr == '+' || opr == '-'){
return 0;
}
return -1;
}
/**
* 判断是否是运算符
* @param val
* @return
*/
public boolean isOpr(char val){
return val == '+' || val == '-' || val == '*' || val == '/';
}
public int cal(int num1,int num2,int opr){
int res = 0; //存放计算结果
switch (opr){
case '+':
res = num1+num2;
break;
case '-':
res = num2-num1;
break;
case '*':
res = num1*num2;
break;
case '/':
res = num2/num1;
break;
default:
break;
}
return res;
}
}