四、栈

1、栈的介绍

 

 

2、栈的应用场景

   1)子程序的调用:在跳往子程序前,会先将下一个指令的地址存储到堆栈中,知道子程序执行完成后再将地址取出,以回到原来的程序中。

   2)处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。

   3)表达式的转换【中缀表达式转成后缀表达式】与求职。

   4)二叉树的遍历。

   5)图形的深度优先(depth-first)搜索法。

3、栈的快速入门

    1)用数组模拟栈的使用,由于栈是一种有序列表,当然可以用数组的数据结构来存储栈的数据内容。

   2)示意图:

   3)代码实现:

package com.stack;

import java.util.Scanner;

public class ArrayStackDemo {
    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack(10);
        String key = "";
        Scanner sc = new Scanner(System.in);
        boolean loop = true;

        while (loop) {
            System.out.println("push:添加数据入栈");
            System.out.println("pop:添加数据出栈");
            System.out.println("list:遍历栈数据");
            System.out.println("exit:退出");
            key = sc.next();
            switch (key) {
                case "push":
                    System.out.println("请输入一个数据");
                    int value = sc.nextInt();
                    arrayStack.push(value);
                    break;
                case "pop":
                    int reval = arrayStack.pop();
                    System.out.println("出栈的数据为:" + reval);
                    break;
                case "list":
                    arrayStack.list();
                    break;
                case "exit":
                    sc.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出~~~~~~~~");
    }
}

//定义一个ArrayStack栈
class ArrayStack {
    private int maxSize;
    private int[] stack;
    private int 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 data) {
        if (isFull()) {
            System.out.println("栈满了,不能加入数据");
            return;
        }
        top++;
        stack[top] = data;
    }

    //出栈
    public int pop() {
        if (isEmpty()) {
            System.out.println("栈空的,不能取数据");
            return 0;
        }
        int redata = stack[top];
        top--;
        return redata;
    }

    //遍历栈
    public void list() {
        if (isEmpty()) {
            System.out.println("栈空的,不能取数据");
            return;
        }
        for (int i = 0; i < stack.length; i++) {
            System.out.printf("stack[%d]=%d
", i, stack[i]);
        }
    }

}

 4、使用栈做一个逆波兰计算器(后缀表达式)

 代码实现:

package com.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNotation {
    public static void main(String[] args) {
        String exp = "4 5 * 8 - 60 + 8 2 / +";
        List<String> list = getListString(exp);
        int res = calculate(list);
        System.out.println("计算结果为:"+res);

    }

    //后缀表达式的计算
    public static int calculate(List<String> ls){
        Stack<String> stack = new Stack<>();
        for(String item:ls){
            if(item.matches("\d+")){//匹配的是多位数
                stack.push(item);
            }else{
                //pop出两个数,并计算,计算完成后再入栈
                int num1 = Integer.parseInt(stack.pop());
                int num2 = Integer.parseInt(stack.pop());
                int result = 0;
                if(item.equals("+")){
                    result = num2+num1;
                }else if(item.equals("-")){
                    result  = num2-num1;
                }else if(item.equals("*")){
                    result = num2*num1;
                }else if(item.equals("/")){
                    result = num2/num1;
                }else{
                    System.out.println("运算符有误");
                }
                stack.push(""+result);
            }
        }
        return Integer.parseInt(stack.pop());
    }

    //将一个后缀表达式,放入到ArrayList中
    public static List<String> getListString(String expression){
        String[] split = expression.split(" ");
        List<String> list = new ArrayList<>();
        for(String s:split){
            list.add(s);
        }
        return list;
    }
}

5、中缀表达式转换后缀表达式

   具体思路步骤如下:

   举例:

 

 代码实现:

//将得到的中缀表达式对应的list转成对应的后缀表达式
    public static List<String> parseSuffixExpression(List<String> ls){
        Stack<String> s1= new Stack<>();//符号栈
        List<String> l1 = new ArrayList<>();//结果栈,存放中间结果
        for(String item:ls){
            if(item.matches("\d+")){
                l1.add(item);
            }else if(item.equals("(")){
                s1.add(item);
            }else if(item.equals(")")){
                //如果是右括号,则依次弹出是s1栈顶的运算符,并压入l1,直到遇到左括号,并消除左括号
                while (!s1.peek().equals("(")){
                    l1.add(s1.pop());
                }
                s1.pop();//弹出左小括号
            }else {//比较运算符的优先级
                //当item的优先级小于等于s1栈顶运算符,将s1栈顶的运算符弹出并加入到l1
                //再比较
                while (s1.size()>0 && getValue(s1.peek()) >= getValue(item)){
                    l1.add(s1.pop());
                }
                //如果是大于当前s1栈顶的优先级,则直接压入
                s1.push(item);
            }
        }
        while(s1.size()!=0){
            l1.add(s1.pop());
        }
        return l1;
    }

    //比较运算符的优先级
    public static int getValue(String operation){
        int result = 0;
        switch (operation){
            case "+":
                result  = 1;
                break;
            case "-":
                result = 1;
                break;
            case "*":
                result = 2;
                break;
            case "/":
                result = 2;
                break;
            default:
                System.out.println("不存在该运算符");
                break;
        }
        return result;
    }
原文地址:https://www.cnblogs.com/zsy-code/p/13511901.html