web-dev-qa-db-ja.com

スタックを使用して1回のスキャンで挿入表現を評価する方法は?

2つのスタックを使用して単一パスで中置式を解決する方法があるかどうかを知りたいですか?スタックは演算子用とオペランド用のどちらでもかまいません...

シャントヤードアルゴリズムで解決する標準的な方法は、中置式を後置(逆ポーランド語)に変換してから解決することです。最初に式を接尾辞に変換したくありません。

式が2*3-(6+5)+8のような場合、どのように解決しますか?

44
nikoo28

かなり遅いですが、答えはここにあります。

2つのスタックを取得します。

  1. operator stack {演算子と括弧の場合}。
  2. operand stack

アルゴリズム

読み取る文字が存在する場合:

  1. 文字がoperandの場合、operand stackを押し、文字が(の場合、operator stackを押します。
  2. それ以外の場合、文字がoperator の場合
    1. operator stackの上部は、この文字よりも優先順位が小さいわけではありません。
    2. operator stackからoperatorをポップします。
    3. op1から2つのoperandsop2およびoperand stack)を取り出します。
    4. op1 op op2operand stackを保存して2.1に戻します。
  3. それ以外の場合、文字が)の場合は、(が見つかるまで2.2-2.4と同じようにします。

それ以外の場合(読み取る文字がなくなりました):

  • operator stackが空になるまで演算子をポップします。
  • Push op1 op op2にトップ2 operandsoperand stackをポップします。

operand stackから最上位の値を返します。

65
Rohit

リンク で指定された方法は本当に良いです。

ソースを引用しましょう:

We will use two stacks:

Operand stack: to keep values (numbers)  and

Operator stack: to keep operators (+, -, *, . and ^).  


In the following, “process” means, (i) pop operand stack once (value1) (ii) pop operator stack once (operator) (iii) pop operand stack again (value2) (iv) compute value1 operator  value2 (v) Push the value obtained in operand stack.          


Algorithm:


Until the end of the expression is reached, get one character and perform only one of the steps (a) through (f):

(a) If the character is an operand, Push it onto the operand stack.

(b) If the character is an operator, and the operator stack is empty then Push it onto the operator stack.

(c) If the character is an operator and the operator stack is not empty, and the character's precedence is greater than the precedence of the stack top of operator stack, then Push the character onto the operator stack.

(d) If the character is "(", then Push it onto operator stack.

(e) If the character is ")", then "process" as explained above until the corresponding "(" is encountered in operator stack.  At this stage POP the operator stack and ignore "(."

(f) If cases (a), (b), (c), (d) and (e) do not apply, then process as explained above.



 When there are no more input characters, keep processing until the operator stack becomes empty.  The values left in the operand stack is the final result of the expression.

これがお役に立てば幸いです!

3
skrtbhtngr
  1. 空の演算子スタックを作成します。
  2. 空のオペランドスタックを作成します。
  3. 入力文字列の各トークンに対して
    a。中置文字列の次のトークンを取得します。
    b。次がオペランドの場合は、オペランドスタックに配置します。
    c。次のトークンが演算子の場合
    • 演算子を評価します。
  4. 演算子スタックは空ではありませんが、演算子とオペランド(左と右)をポップし、左演算子を右に評価し、結果をオペランドスタックにプッシュします。
  5. 演算子スタックからポップ結果。
1
nikhil

以下は、Javaで中置式を評価する試みです。バグを見つけたら教えてください:)

import Java.util.*;

public class ArithmeticExpressionEvaluation {

    public static void main(String[] args) {
        Scanner readExpression = new Scanner(System.in);
        System.out.print("Enter the expression: ");
        String expression = readExpression.nextLine();
        System.out.println(expression);
        System.out.println("Result: " + calculateExpression(expression));
    }

    public static long calculateExpression(String expression) {

        Stack<Long> operandStack = new Stack<>();
        Stack<Character> operatorStack = new Stack<>();

        if (!isValidExpression(expression)) {
            System.out.println("Not a valid expression to evaluate");
            return 0;
        }

        int i = 0;
        String currentInteger = null;
        while (i < expression.length()) {

            // System.out.println(expression.charAt(i));
            if (expression.charAt(i) >= '0' && expression.charAt(i) <= '9') {

                currentInteger = expression.charAt(i) + "";
                i++;
                while (i != expression.length() && (expression.charAt(i) >= '0' && expression.charAt(i) <= '9')) {
                    currentInteger = currentInteger + expression.charAt(i);
                    i++;
                }

                operandStack.Push(Long.parseLong(currentInteger));
            } else {

                if (expression.charAt(i) == ')') {

                    while (operatorStack.peek() != '(') {
                        performArithmeticOperation(operandStack, operatorStack);
                    }
                    operatorStack.pop();
                } else {

                    Character currentOperator = expression.charAt(i);
                    Character lastOperator = (operatorStack.isEmpty() ? null : operatorStack.peek());


                    if (lastOperator != null && checkPrecedence(currentOperator, lastOperator)) {
                        performArithmeticOperation(operandStack, operatorStack);
                    }
                    operatorStack.Push(expression.charAt(i));

                }
                i++;
            }

        }


        while (!operatorStack.isEmpty()) {
            performArithmeticOperation(operandStack, operatorStack);
        }

    //    System.out.println(Arrays.toString(operandStack.toArray()));
    //    System.out.println(Arrays.toString(operatorStack.toArray()));

        return operandStack.pop();

    }

    public static void performArithmeticOperation(Stack<Long> operandStack, Stack<Character> operatorStack) {
        try {
            long value1 = operandStack.pop();
            long value2 = operandStack.pop();
            char operator = operatorStack.pop();

            long intermediateResult = arithmeticOperation(value1, value2, operator);
            operandStack.Push(intermediateResult);
        } catch (EmptyStackException e) {
            System.out.println("Not a valid expression to evaluate");
            throw e;
        }
    }


    public static boolean checkPrecedence(Character operator1, Character operator2) {

        List<Character> precedenceList = new ArrayList<>();
        precedenceList.add('(');
        precedenceList.add(')');
        precedenceList.add('/');
        precedenceList.add('*');
        precedenceList.add('%');
        precedenceList.add('+');
        precedenceList.add('-');


        if(operator2 == '(' ){
            return false;
        }

        if (precedenceList.indexOf(operator1) > precedenceList.indexOf(operator2)) {
            return true;
        } else {
            return false;
        }

    }

    public static long arithmeticOperation(long value2, long value1, Character operator) {

        long result;

        switch (operator) {

            case '+':
                result = value1 + value2;
                break;

            case '-':
                result = value1 - value2;
                break;

            case '*':
                result = value1 * value2;
                break;

            case '/':
                result = value1 / value2;
                break;

            case '%':
                result = value1 % value2;
                break;

            default:
                result = value1 + value2;


        }
        return result;
    }


    public static boolean isValidExpression(String expression) {

        if ((!Character.isDigit(expression.charAt(0)) && !(expression.charAt(0) == '('))
                || (!Character.isDigit(expression.charAt(expression.length() - 1)) && !(expression.charAt(expression.length() - 1) == ')'))) {
            return false;
        }

        HashSet<Character> validCharactersSet = new HashSet<>();
        validCharactersSet.add('*');
        validCharactersSet.add('+');
        validCharactersSet.add('-');
        validCharactersSet.add('/');
        validCharactersSet.add('%');
        validCharactersSet.add('(');
        validCharactersSet.add(')');

        Stack<Character> validParenthesisCheck = new Stack<>();

        for (int i = 0; i < expression.length(); i++) {

            if (!Character.isDigit(expression.charAt(i)) && !validCharactersSet.contains(expression.charAt(i))) {
                return false;
            }

            if (expression.charAt(i) == '(') {
                validParenthesisCheck.Push(expression.charAt(i));
            }

            if (expression.charAt(i) == ')') {

                if (validParenthesisCheck.isEmpty()) {
                    return false;
                }
                validParenthesisCheck.pop();
            }
        }

        if (validParenthesisCheck.isEmpty()) {
            return true;
        } else {
            return false;
        }
    }
}
1
learner