[Java アルゴリズム] スタック / フロント、ミドル、サフィックス

スタック

需要紹介
ここに画像の説明を挿入

スタックの紹介ここに画像の説明を挿入

スタックの適用シナリオ
ここに画像の説明を挿入

ポップアンドプッシュ

ここに画像の説明を挿入

package ArrayStack;

import java.net.Socket;
import java.util.Scanner;

public class ArrayStackDemo {
    
    
    public static void main(String[] args) {
    
    
        //测试一下ArrayStack是否正确
        //先创建栈
        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 value = scanner.nextInt();
                    stack.push(value);
                    break;
                case "pop":
                    try{
    
    
                        int res = stack.pop();
                        System.out.printf("出栈的数据是%d\n",res);
                    }catch (Exception e){
    
    
                        System.out.println(e.getMessage());
                    }
                    break;
                case "exit":
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出!");
    }

}
class ArrayStack{
    
    
    private int maxSize;    //栈的大小
    private int[] stack;    //数组模拟栈,数据就放在该数组里面
    private int top = -1;    //top表示栈顶 初始化为-1

    //构造器
    public ArrayStack(int maxSize){
    
    
        this.maxSize = maxSize;
        stack = new int[this.maxSize];
    }

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

    //入栈-push
    public void push(int value){
    
    
        //先判断栈是否满
        if (isFull()){
    
    
            System.out.println("栈满");
            return;
        }
        top++;
        stack[top] = value;
    }
    //出栈-pop  讲栈顶的数据返回
    public int pop(){
    
    
        //先判断栈是否为空
        if (isEmpty()){
    
    
            //抛出异常
            throw new RuntimeException("栈空 没有数据!");
        }
        int value = stack[top];
        top --;
        return value;
    }

    //显示栈的情况[遍历栈] 从栈顶开始显示数据
    public void list(){
    
    
        if (isEmpty()){
    
    
            System.out.println("栈空 没有数据!");
            return;
        }
        //需要从栈顶开始显示数据
        for (int i = maxSize-1; i >= 0; i--) {
    
    
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
    }
}

演習 – リンク リスト シミュレーション スタック

ここに画像の説明を挿入
他の人の理解を読んだ後、私はとても眠いです:

リンクされたリストオーバーを使用することです. 先頭の挿入方法は、スタックの先頭を挿入することと同等であり、スタックをポップすることは...と同等です.

class SingleLinkedListStack {
    
    
    private Node top = new Node(-1);// 定义一个头指针代表栈顶

    // 判断栈是否为空
    public boolean isEmpty() {
    
    
        return top.getNext() == null;
    }

    // 入栈,入栈的时候采用头插法
    public void push(Node node) {
    
    

        if (top.getNext() == null) {
    
    // 第一个节点的插入
            top.setNext(node);
            return;
        }
        // 头插法
        Node temp = top.getNext();// 定义一个临时变量使其指向top节点的下一个节点
        top.setNext(node);
        node.setNext(temp);

    }
    
    // 出栈
    public void pop() {
    
    
        if (top.getNext() == null) {
    
    
            System.out.println("栈为空!不能出栈!");
            return;
        }
        System.out.println("节点为:" + top.getNext().getValue());
        top = top.getNext();
    }

    // 遍历栈
    public void show() {
    
    
        if (isEmpty()) {
    
    
            System.out.println("栈为空!");
            return;
        }
        Node temp = top;
        while (temp.getNext() != null) {
    
    
            System.out.println("节点为:" + temp.getNext().getValue());
            temp = temp.getNext();
        }
    }

}

スタックは包括的な電卓を実装します

ここに画像の説明を挿入
眠い時にアルゴリズムをするのは難しい…

package ArrayStack;

public class Calculator {
    
    
    public static void main(String[] args) {
    
    
        String expression = "3+2*6-2";
        //创建两个栈 数栈 符号栈
        ArrayStack2 numStack = new ArrayStack2(10);
        ArrayStack2 operStack = new ArrayStack2(10);
        //定义需要的相关变量
        int index = 0;//用于扫面
        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int res = 0;//存放结果
        char ch = ' ';//讲每次扫描得到的char保存到ch中
        String keepNum = "";

        //开始while喜欢扫描expression
        while (true){
    
    
            //依次得到expression的每一个字符
            ch = expression.substring(index,index+1).charAt(0);//转为char
            //判断ch是什么,然后做相应的处理
            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 {
    
    //如果是数 则直接进入数栈
                //处理多位数 (而不是就压入一个字符就跑路
                keepNum += ch;
                //处理当处于最后一位数的越界情况
                if (index == expression.length()  -1){
    
    
                    numStack.push(Integer.parseInt(keepNum));
                }else {
    
    
                    //判断下一个字符是不是数字
                    if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
    
    
                        //如果下一位是运算符 则让这一位数入数栈
                        numStack.push(Integer.parseInt(keepNum));
                        //keepNum清空(很重要
                        keepNum = "";
                    }
                }
            }

            //让index向后扫描 并判断是否到expression最后
            index ++;
            if (index >= expression.length()){
    
    
                break;
            }
        }
        //当表达式扫描完毕后 就顺序从 数栈 和 符号栈 中pop相应的数和符号并运行
        while (true){
    
    
            //如果符号栈为空
            if (operStack.isEmpty()){
    
    
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = numStack.cal(num1,num2,oper);
            numStack.push(res);//入栈
        }
        //将数栈最后的数 pop出 就是结果
        int res2 = numStack.pop();
        System.out.printf("表达式%s = %d",expression,res2);
    }
}
class ArrayStack2{
    
    
    private int maxSize;    //栈的大小
    private int[] stack;    //数组模拟栈,数据就放在该数组里面
    private int top = -1;    //top表示栈顶 初始化为-1

    //构造器
    public ArrayStack2(int maxSize){
    
    
        this.maxSize = maxSize;
        stack = new int[this.maxSize];
    }

    //拓展方法
    //返回当前栈顶的值,但没有做pop
    public int peek(){
    
    
        return stack[top];
    }
    //字符优先级返回
    public int priority(int oper){
    
    
        if (oper == '*' || oper == '/'){
    
    
            return 1;
        }else if (oper == '+' || oper == '-'){
    
    
            return 0;
        }else {
    
    
            return -1;
        }
    }
    //判断是不是一个运算符
    public boolean isOper(char val){
    
    
        return val =='+'||val =='-'||val == '*'||val == '/';
    }
    //计算
    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;
    }

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

    //入栈-push
    public void push(int value){
    
    
        //先判断栈是否满
        if (isFull()){
    
    
            System.out.println("栈满");
            return;
        }
        top++;
        stack[top] = value;
    }
    //出栈-pop  讲栈顶的数据返回
    public int pop(){
    
    
        //先判断栈是否为空
        if (isEmpty()){
    
    
            //抛出异常
            throw new RuntimeException("栈空 没有数据!");
        }
        int value = stack[top];
        top --;
        return value;
    }

    //显示栈的情况[遍历栈] 从栈顶开始显示数据
    public void list(){
    
    
        if (isEmpty()){
    
    
            System.out.println("栈空 没有数据!");
            return;
        }
        //需要从栈顶开始显示数据
        for (int i = maxSize-1; i >= 0; i--) {
    
    
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
    }
}

プレフィックス、インフィックス、サフィックスの規則

プレフィックス (ポーランド語表現ここに画像の説明を挿入
ここに画像の説明を挿入

中置記号 (人間が最も一般的に使用する
ここに画像の説明を挿入

逆ポーランド式の実装電卓

導入の
ここに画像の説明を挿入
アイデア:
ここに画像の説明を挿入

プレフィックスとサフィックスの違い
ここに画像の説明を挿入

ケースの要件:

ここに画像の説明を挿入

コード

package zhui;

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

public class PolandNotation {
    
    
    public static void main(String[] args) {
    
    
        //声明一个波兰表达式
        String suffixExpression = "3 4 + 5 * 6 -";

        List<String> List = getListString(suffixExpression);
        System.out.println("List = "+List);
        System.out.println();
        int res = calculate(List);
        System.out.println("计算结果 = "+res);
    }

    //将逆波兰表达式,放入到ArrayList中
    private static List<String> getListString(String suffixExpression) {
    
    
        //将suffixExpression分割
        String[] split = suffixExpression.split(" ");
        List<String> list = new ArrayList<String>();

        for (String ele:split){
    
    
//            System.out.println("ele="+ele);
            list.add(ele);
        }
        return list;
    }
    public static int calculate(List<String> ls){
    
    
        //创建一个栈(就一个栈就够了
        Stack<String> stack = new Stack<String>();
        //遍历ls
        for (String item:ls){
    
    
            //利用正则表达式取出数
            if (item.matches("\\d+")){
    
    //匹配多位数
                //入栈
                stack.push(item);
            }
            //当item为操作符时
            else {
    
    
                //pop出两个数 运算后入栈(按后缀所以先弹出的是num2
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res = 0;
                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("运算符有误!");
                }
                //int转String
                //两种写法
                stack.push(res+"");
//                stack.push(""+res);
            }
        }
        //最后留在stack中的数据是运算结果
        return Integer.parseInt(stack.pop());
    }
}

ここに画像の説明を挿入

接尾辞へのインフィックス


ここに画像の説明を挿入
主な外部メソッドを考えました:

1.最初に中置式をリストに入れます

    //将中缀表达式转为对应的List
    public static List<String> toInfixExpressionList(String s){
    
    
        //定义一个List
        List<String> ls = new ArrayList<String>();
        int i = 0;  //一个指针 用于遍历中缀表达式字符串
        String str; //对多位数进行拼接
        char c; //没遍历一个字符 就放入到c中

        //do-while和while结果一样
//        do {
    
    
//            //如果c是一个非数字 直接加入ls中
//            if ((c=s.charAt(i)) < 48 || (c=s.charAt(i)) > 57){
    
    
//                ls.add(""+c);
//                i++;
//            }else { //如果是一个数 需要考虑多位数
//                str = "";//先置为空
//                while (i<s.length() && (c=s.charAt(i))>=48 && (c=s.charAt(i)) <= 57){
    
    
//                    str += c;//拼接
//                    i++;
//                }
//                ls.add(str);
//            }
//        }while (i < s.length());
        while (i < s.length()){
    
    
            //如果c是一个非数字 直接加入ls中
            if ((c=s.charAt(i)) < 48 || (c=s.charAt(i)) > 57){
    
    
                ls.add(""+c);
                i++;
            }else {
    
     //如果是一个数 需要考虑多位数
                str = "";//先置为空
                while (i<s.length() && (c=s.charAt(i))>=48 && (c=s.charAt(i)) <= 57){
    
    
                    str += c;//拼接
                    i++;
                }
                ls.add(str);
            }
        }
        return ls;
    }

主な方法:

String expression = "1+((2+3)*4)-5";
        List<String> infixExpressionList = toInfixExpressionList(expression);
        System.out.println(infixExpressionList);

2.次に、リストをサフィックスに変換します

主な方法

//方法:将得到的中缀表达式对应的List 转为 后缀表达式的List
    public static List<String> parseSuffixExpressionList(List<String> ls){
    
    
        //定义两个栈
        Stack<String> s1 = new Stack<String>(); //符号栈
        //说明:为什么不用Stack2
        //因为s2这个栈 在整个转换过程中 没有pop操作 而且后面我们还需要逆序输出
        //因此很麻烦 这里我们就不用Stack直接用List
        List<String> s2 = new ArrayList<String>();
        //遍历ls
        for (String item:ls){
    
    
            //如果是一个数 加入s2
            if (item.matches("\\d+")){
    
    
                s2.add(item);
            }else if (item.equals("(")){
    
    
                s1.push(item);
            }else if (item.equals(")")){
    
    
                //如果是右括号,则依次弹出s1栈顶的运算符 压入s2中 直到遇到左括号为止 此时将这一对括号丢弃
                while (!s1.peek().equals("(")){
    
    //peek去栈顶元素
                    s2.add(s1.pop());
                }
                s1.pop(); //将(弹出s1栈 等价于消除小括号
            }
            else {
    
    //当遇到运算符时
                //当item优先级小于等于s1栈顶运算符,将s1栈顶的运算符弹出并加入到s2中 再次转到(4.1)步骤
                //与s1中新的栈顶运算符相比较
                while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){
    
    
                    s2.add(s1.pop());
                }
                //将item压入栈
                s1.push(item);
            }
        }
        //将s1中剩余的运算符依次弹出加入到s2中
        while (s1.size() != 0){
    
    
            s2.add(s1.pop());
        }
        return s2;//因为是放到List中的 所以顺序输出下为后缀表达式
    }

演算子の優先順位を判断するためのクラス

class Operation{
    
    
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;

    public static int getValue(String operation){
    
    
        int res = 0;
        switch(operation){
    
    
            case "+":
                res = ADD;
                break;
            case "-":
                res = SUB;
                break;
            case "*":
                res = MUL;
                break;
            case "/":
                res = DIV;
                break;
            default:
                System.out.println("不存在该运算符");
                break;
        }
        return res;
    }

}

主に

System.out.println();
        List<String> suffixExpressionList = parseSuffixExpressionList(infixExpressionList);
        System.out.println("后缀表达式对应的List" + suffixExpressionList);

おすすめ

転載: blog.csdn.net/m0_65431212/article/details/128643965