数据结构与算法(Java)之栈

数组实现栈

package com.weeks.stack;

import java.util.Scanner;

/**
 * @author 达少
 * @version 1.0
 */
public class ArrayStackDemo {
    public static void main(String[] args) {
        //创建栈
        ArrayStack arrayStack = new ArrayStack(4);
        //创建输入扫描器,并接收用户输入
        Scanner scanner = new Scanner(System.in);
        char key = ' ';
        //控制while循环
        boolean loop = true;
        //测试各个方法
        while(loop){
            System.out.println("\n栈操作方法菜单:\n" +
                    "1 push 数据入栈\n" +
                    "2 pop  数据出栈\n" +
                    "3 list 显示栈中数据\n" +
                    "4 exit 退出程序\n");
            System.out.print("请输入你的选择:");
            key = scanner.next().charAt(0);
            switch (key){
                case '1':
                    System.out.print("请输入一个整数:");
                    int value = scanner.nextInt();
                    arrayStack.push(value);
                    break;
                case '2':
                    try {
                        int res = arrayStack.pop();
                        System.out.printf("本次出栈的数据为:%d\n", res);
                    } catch (Exception e) {
                        System.out.println(e);
                    }
                    break;
                case '3':
                    arrayStack.list();
                    break;
                case '4':
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("退出程序~~~");
    }
}

class ArrayStack{
    private int maxSize;//表示栈的容量
    private int top = -1;//表示栈顶,默认值为-1
    private int[] stack;//使用数组模拟栈

    //在有参构造方法中初始化栈
    public ArrayStack(int maxSize){
        this.maxSize = maxSize;
        this.stack = new int[this.maxSize];
    }

    //满栈判断
    public boolean isFull(){
        return top == maxSize - 1;
    }

    //空栈判断
    public boolean isEmpty(){
        return top == -1;
    }

    //数据入栈
    public void push(int value){
        //判断是否满栈
        if(isFull()){
            System.out.println("已满栈,无法入栈!!!");
            return;
        }
        //入栈
        stack[++top] = value;
    }

    //数据出栈
    public int pop(){
        //判断是否栈空
        if(isEmpty()){
            throw new RuntimeException("栈已空,没有数据可以出栈!!!");
        }
        //出栈过程
        //1.将出栈数据赋值给临时变量
        int res = stack[top];
        //2.top下移
        top--;
        //3.将出栈数据返回
        return res;
    }

    //遍历栈
    public void list(){
        //判断栈是否为空
        if(isEmpty()){
            System.out.println("栈已空,没有数据可遍历!!!");
            return;
        }
        //遍历
        for(int i = top; i > -1; i--){
            System.out.printf("arr[%d]=%d\n", i, stack[i]);
        }
    }
}

单链表实现栈

package com.weeks.stack;

import java.util.Scanner;

/**
 * @author 达少
 * @version 1.0
 * 使用单链表的头插法实现栈
 */
public class LinkedListStackDemo {
    public static void main(String[] args) {
        //创建栈
        LinkedListStack stack = new LinkedListStack();
        //创建输入扫描器,并接收用户输入
        Scanner scanner = new Scanner(System.in);
        char key = ' ';
        //控制while循环
        boolean loop = true;
        //测试各个方法
        while(loop){
            System.out.println("\n栈操作方法菜单:\n" +
                    "1 push 数据入栈\n" +
                    "2 pop  数据出栈\n" +
                    "3 list 显示栈中数据\n" +
                    "4 exit 退出程序\n");
            System.out.print("请输入你的选择:");
            key = scanner.next().charAt(0);
            switch (key){
                case '1':
                    System.out.print("请输入一个整数:");
                    int value = scanner.nextInt();
                    stack.push(value);
                    break;
                case '2':
                    try {
                        int res = stack.pop();
                        System.out.printf("本次出栈的数据为:%d\n", res);
                    } catch (Exception e) {
                        System.out.println(e);
                    }
                    break;
                case '3':
                    stack.list();
                    break;
                case '4':
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("退出程序~~~");
    }
}

class LinkedListStack{
    //头节点不存储具体的数据
    private Node head = new Node(0);

    //空栈判断
    public boolean isEmpty(){
        return head.getNext() == null;
    }

    //入栈使用头插法插入链表
    public void push(int value){
        //创建入栈节点
        Node node = new Node(value);
        //插入到链表的头节点下一个位置
        node.setNext(head.getNext());
        head.setNext(node);
    }

    //出栈,因为使用头插法入栈,所以要从链表的头节点的下一个位置开始出栈
    public int pop(){
        //判断是否空栈
        if (isEmpty()){
            throw new RuntimeException("栈已空,没有数据可以出栈!!!");
        }
        //出栈
        //1.将要出栈的节点数据赋值给临时变量
        int res = head.getNext().getData();
        //2.将出栈的节点从链表中删除
        head.setNext(head.getNext().getNext());
        return res;
    }

    //遍历栈,从头节点的下一个位置开始输出链表数据
    public void list(){
        //判断是否空栈
        if(isEmpty()){
            System.out.println("栈已空,不可遍历!!!");
            return;
        }
        //头节点不能动,需要定义辅助变量遍历栈
        Node cur = head.getNext();
        while(cur != null){
            System.out.println(cur);
            //下移cur
            cur = cur.getNext();
        }
    }
}

class Node{
    private int data;
    private Node next;

    public Node(int data){
        this.data = data;
    }
    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Node = " + data;
    }
}

栈实现综合计算器

中缀表达式

package com.weeks.stack.calculator;

/**
 * @author 达少
 * @version 1.0
 * 使用栈实现综合计算(中缀表达式的计算)
 */
public class CalculatorDemo {
    public static void main(String[] args) {
        //创建数栈
        LinkedListStack numStack = new LinkedListStack();
        //创建符号栈
        LinkedListStack operatorStack = new LinkedListStack();

        //计算表达式
        String expression = "700+2*6-2";

        //创建辅助变量
        int index = 0;//帮助扫描计算表达式
        char curChar = ' ';
        String keepNum = "";//定义变量拼接数字符号
        //扫描计算表达式,入栈规则:
        //1.当所扫描的字符是数字,可以直接压入数栈中
        //2.当所扫描的字符是操作符,有三种情况:
        //  1)当符号栈为空栈时,当前操作符直接压入符号栈中
        //  2)当前操作符的优先级小于或等栈顶的操作符时,将栈顶操作符弹出,
        //    并在数栈中弹出两个数,进行运算,将运算的结果压入数栈中,并将当前操作符压入符号栈
        //  3)当前操作符的优先级大于栈顶的操作符时,当前操作符直接入栈
        while(index < expression.length()){
            //将当前index位置的字符取出
            curChar = expression.substring(index, index+1).charAt(0);
            //判断当前的字符是否为操作符
            if(operatorStack.isOperator(curChar)){
                //当符号栈为空栈时,当前操作符直接压入符号栈中
                if (operatorStack.isEmpty()){
                    operatorStack.push(curChar);
                }else if(operatorStack.priority(curChar) <= operatorStack.priority((char) operatorStack.getTop())){
                    //当前操作符的优先级小于或等栈顶的操作符时,将栈顶操作符弹出,
                    //并在数栈中弹出两个数,进行运算,将运算的结果压入数栈中,并将当前操作符压入符号栈
                    char opr = (char) operatorStack.pop();
                    int num1 = 0;
                    int num2 = 0;
                    try {
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    int res = numStack.calculate(num1, num2, opr);
                    numStack.push(res);
                    operatorStack.push(curChar);
                }else{
                    operatorStack.push(curChar);
                }
            }else{//当前字符为数字
                //当前的字符是数字也分两种情况:
                //1.字符串已经到末尾了
                //2.字符串还没到末尾,下一个字符也是数字
                //numStack.push(curChar - 48);//ascii码表
                if(index == expression.length() - 1){
                    //1.字符串已经到末尾了,当前字符直接入栈
                    numStack.push(curChar - 48);//ascii码表
                }else{
                    //当前数字符号与keepNum拼接
                    keepNum += curChar;
                    //判断下一个字符的类型
                    char nextChar = expression.substring(index+1, index+2).charAt(0);
                    if(operatorStack.isOperator(nextChar)){
                        //如果下一个是符号类型将当前的字符串数字直接入栈
                        numStack.push(Integer.parseInt(keepNum));
                        //入栈后要清空keepNum
                        keepNum = "";
                    }
                }
            }
            index++;//index自增
        }
        while(true){
            if(operatorStack.isEmpty()){
                break;
            }
            char opr = (char) operatorStack.pop();
            int num1 = numStack.pop();
            int num2 = numStack.pop();
            int res = numStack.calculate(num1, num2, opr);
            numStack.push(res);
        }
        System.out.printf("计算的结果%s = %d", expression, numStack.pop());
    }
}

class LinkedListStack{
    //头节点不存储具体的数据
    private Node head = new Node(-1);

    //空栈判断
    public boolean isEmpty(){
        return head.getNext() == null;
    }

    //入栈使用头插法插入链表
    public void push(int value){
        //创建入栈节点
        Node node = new Node(value);
        //插入到链表的头节点下一个位置
        node.setNext(head.getNext());
        head.setNext(node);
    }

    //出栈,因为使用头插法入栈,所以要从链表的头节点的下一个位置开始出栈
    public int pop(){
        //判断是否空栈
        if (isEmpty()){
            throw new RuntimeException("栈已空,没有数据可以出栈!!!");
        }
        //出栈
        //1.将要出栈的节点数据赋值给临时变量
        int res = head.getNext().getData();
        //2.将出栈的节点从链表中删除
        head.setNext(head.getNext().getNext());
        return res;
    }

    //遍历栈,从头节点的下一个位置开始输出链表数据
    public void list(){
        //判断是否空栈
        if(isEmpty()){
            System.out.println("栈已空,不可遍历!!!");
            return;
        }
        //头节点不能动,需要定义辅助变量遍历栈
        Node cur = head.getNext();
        while(cur != null){
            System.out.println(cur);
            //下移cur
            cur = cur.getNext();
        }
    }

    //要实现计算器的功能需要增加的方法
    //获取栈顶元素的方法
    public int getTop(){
        //判断是否空栈
        if(head.getNext() == null){
            throw new RuntimeException("栈空,没有栈顶元素!!!");
        }
        return head.getNext().getData();
    }
    //比较运算符的优先级
    public int priority(char operator){
        if (operator == '*' || operator == '/'){
            return 1;
        }else if(operator == '+' || operator ==  '-'){
            return 0;
        }else{
            throw new RuntimeException("输入的不是操作符!!!");
        }
    }

    //判断输入的符号是不是操作符
    public boolean isOperator(char operator){
        return operator == '*' || operator == '/' || operator == '+' || operator == '-';
    }

    //输入两个数和一个符号进行计算
    public int calculate(int num1, int num2, char operator){
        int res = 0;
        switch (operator){
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;//注意顺序
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;//注意顺序
                break;
            default:
                break;

        }
        return res;
    }
}

class Node{
    private int data;
    private Node next;

    public Node(int data){
        this.data = data;
    }
    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Node = " + data;
    }
}

逆波兰表达式(后缀表达式)

package com.weeks.stack.calculator;

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

/**
 * @author 达少
 * @version 1.0
 * 使用逆波兰表达式(后缀表达式)计算
 */
public class AntiPolandExpressionCalculate {
    public static void main(String[] args) {
        //中缀表达式
        String inSuffixExpression = "3*(400+5)-3+6*7/2+6";
        List<String> strings = changeInSuffixToList(inSuffixExpression);
        System.out.println(strings);
        List<String> suffixList = parseToSuffixExpression(strings);
        System.out.println(suffixList);
        //计算
        int result = calculate(suffixList);
        System.out.printf("%s = %d", inSuffixExpression, result);
        //逆序表达式,表达式的每一个整体的字符以空格隔开,方便后面以空格分割成数组
//        String suffixExpression = "30 4 + 5 * 6 -";
//        List<String> list = getList(suffixExpression);
//        System.out.println(list);
//        int res = calculate(list);
//        System.out.println("res = " + res);
    }

    //将后缀表达式转化为一个List
    public static List<String> getList(String suffixExpression){
        //先将后缀表达式转换成数组
        String[] splits = suffixExpression.split(" ");
        //创建List对象
        List<String> strings = new ArrayList<>();
        //将splits数组中的每个元素放进List中
        for(String str : splits){
            strings.add(str);
        }
        return strings;
    }

    //后缀表达式计算过程
    public static int calculate(List<String> strings){
        //创建一个栈,使用系统提供的栈
        Stack<String> nums = new Stack<>();
        for(String item : strings){
            //如果item是数字将其入栈
            if(item.matches("\\d+")){
                nums.add(item);
            }else{
                //当item是符号时,将栈中的两个数弹出,注意顺序
                int num2 = Integer.parseInt(nums.pop());
                int num1 = Integer.parseInt(nums.pop());
                int res = 0;
                //根据item选择操作
                if(item.equals("+")){
                    res = num1 + num2;
                }else if(item.equals("-")){
                    res = num1 - num2;
                }else if(item.equals("*")){
                    res = num1 * num2;
                }else if(item.equals("/")){
                    res = num1 / num2;
                }else{
                    throw new RuntimeException("表达式的符号有误,请检查!!!");
                }
                //将结果入栈
                nums.push("" + res);
            }
        }
        return Integer.parseInt(nums.pop());
    }

    //将中缀表达式转换为一个List列表,方便之后的操作
    public static List<String> changeInSuffixToList(String inSuffixExpression){
        //定义List对象
        List<String> strings = new ArrayList<>();
        //一个索引用于遍历中缀表达式
        int index = 0;
        //定义变量记录当前字符
        char curChar = ' ';
        //定义一个变量用于拼接数字
        String num = "";
        //遍历中缀表达式
        while(index < inSuffixExpression.length()){
            //扫描当前索引字符
            curChar = inSuffixExpression.substring(index, index+1).charAt(0);
            //当前扫描的字符是符号时,将其直接加入strings中
            if(curChar < 48 || curChar > 57){//0-9的编码就是48-57
                strings.add(curChar + "");
            }else{//当前字符是数字
                //先判断是否是字符串的最后一个字符
                if(index == inSuffixExpression.length() - 1){
                    //是最后一个字符,将其直接加入strings中
                    strings.add(curChar + "");
                }else{//不是最后一个字符
                    num += curChar;
                    //判断下一个字符是否是数字
                    char next = inSuffixExpression.substring(index+1, index+2).charAt(0);
                    if(next < 48 || next > 57){//不是一个数字
                        //将num加入strings中
                        strings.add(num);
                        //将num置空
                        num = "";
                    }
                }
            }
            index++;
        }
        return strings;
    }

    //将中缀表达式的列表转换为后缀表达式列表
    public static List<String> parseToSuffixExpression(List<String> inSuffixList){
        //定义一个栈操作符号
        Stack<String> oprStack = new Stack<>();
        //定义一个栈操作数字
//        Stack<String> numStack = new Stack<>();
        //但是数字栈没有弹出操作,为了后期方便可以不使用栈,可以使用列表代替数字栈
        List<String> resList = new ArrayList<>();
        //遍历中缀表达式列表
        //如果是数字直接加入结果列表中
        //如果是符号:
        //  1.如果是空栈或者是“(” 直接加入符号栈中
        //  2.如果当前的符号优先级小于或等于栈顶的符号时,将栈中的符号出栈加入列表,再将当前的符号入栈
        //  3.如果当前的符号是“)”将符号栈的符号出栈,直到遇到“(”停止出栈
        //遍历中缀表达式列表
        for(String item : inSuffixList){
            if(item.matches("\\d+")){//如果是数字
                resList.add(item);
            }else{//如果是字符
                //如果是栈空或当前的字符值“(”
                if(oprStack.isEmpty() || item.equals("(")){
                    oprStack.push(item);
                }else{
                    if(item.equals(")")){//")"不用加入栈中
                        while(!(oprStack.peek().equals("("))){
                            resList.add(oprStack.pop());
                        }
                        oprStack.pop();//去除“(”
                    }else if(oprStack.peek().equals("(")){
                        //当栈顶是“(”时该符号直接加入栈中
                        oprStack.push(item);
                    }else {
                        int priority = Priority.getPriority(item);
                        //优先级比较:优先级小于或等于栈顶元素
                        if( priority <= Priority.getPriority(oprStack.peek())) {
                            //将比item优先级高的全部弹出加入列表中
                            while(!oprStack.isEmpty() && priority <= Priority.getPriority(oprStack.peek())) {
                                resList.add(oprStack.pop());
                            }
                            //将item入栈
                            oprStack.push(item);
                        }else{
                            oprStack.push(item);
                        }
                    }
                }
            }
        }
        //将符号栈的所有字符出栈加入列表中
        while(!oprStack.isEmpty()){
            resList.add(oprStack.pop());
        }
        return resList;
    }
}

//定义优先级类
class Priority{
    //数字越大优先级越高
    private static final int ADD = 1;
    private static final int SUB = 1;
    private static final int MUL = 2;
    private static final int DIV = 2;

    public static int getPriority(String key){
        switch (key){
            case "+":
                return ADD;
            case "-":
                return SUB;
            case "*":
                return MUL;
            case "/":
                return DIV;
            default:
                throw new RuntimeException("没有该类型的操作符!!!");
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值