简体   繁体   中英

Re-Order array based on priority in Java

Hi I have been working on my Java calculator. It now puts all the operands and operators in different arrays and I also have an array with the priority of each operator.

For example * and / are 1 and + and - are 2.
So if my operator array holds '[/, +, +, *]'
My priority array holds '[1, 2, 2, 1]'

The part I have come stuck on is I now need to make sure my calculator can reorder the operators so I can work through my calculateResult and make sure the operators are in the correct order.

The part I am asking for help with is calculate result. I cant figure out how to go about doing this so that it calculates it in the correct order.

import java.util.*;
public class stringCalculator {

    //String containing the input from the user
    private String userinput;
    //List to store the operators in
    private ArrayList<String> calcOperator = new ArrayList<String>();
    //List to store the operands in
    private ArrayList<Integer> calcOperand = new ArrayList<Integer>();
    //Array to store all the integers in
    private String[] integers;
    //Array to store all the operators in
    private String[] operators;
    //Array to store the priority value
    private String[] priorityList;

    public stringCalculator(String userinput){
        this.userinput = userinput;
        //System.out.println(userinput);
        integers = userinput.split("[+-/*///]");
        operators = userinput.split("\\d+");
    }   

    //This function will check the input and return true if the user enters a correct expression.
    public boolean checkInput(){
        boolean show = userinput.matches("[-+/*0-9]+");
        return show;
    }

    //This function will add any numbers in the string to the calcOperand array.
    //and any operators to the calcOperator field.
    public void parseInput(String[] item){
        for (String op : item){
            if (op.matches("\\d+")){
                calcOperand.add(Integer.parseInt(op));
            }
            //operators go into calcOperators.
            else if (op.equals("+")||op.equals("-")||op.equals("*")||op.equals("/")){
                calcOperator.add(op);
            }
            else{//everything else is ignored and left. 
            }
        }
    }

    //Function to calculate the priority of each operator.
    //For example * and / will be 1, and + and - will be 2.
    public void calculatePriority(){
        priorityList = calcOperator.toArray(new String[calcOperator.size()]);
        for (int i = 0; i<priorityList.length; i++){
            if (priorityList[i].equals("+")){
                priorityList[i] = "2";
            }else if (priorityList[i].equals("-")) {
                    priorityList[i] = "2";
            }else if (priorityList[i].equals("/")){
                priorityList[i] = "1";
            }else if (priorityList[i].equals("*")){
                priorityList[i] = "1";
            }else{
                System.out.println("error");
            }
        }
    }
    public void printPri(){

        for (String s : priorityList)
            System.out.print(s +",");
    }

    //Function to show the result of the expression.
    public void calculateResult(){
        if(checkInput()){
            parseInput(integers);
            parseInput(operators);
            System.out.println("Operands: " + calcOperand);
            System.out.println("Operators: " + calcOperator);
            calculatePriority();
            System.out.print("Priority: ");
            printPri();
        }else{
            System.out.println("Please enter a valid input!");

        }
    }

}

The right way to do this would be to parse the input into an AST (abstract syntax tree). Then evaluation of the expressions is done in the right order.

The propensity to attempt to reduce all problems to tabular solutions is a huge anti pattern that, sadly, many programmers never learn. Not everything is a table. There are trees and graphs out there too.

Pretty much all parsing jobs should result in the construction of a tree (which may or may not be an implementation of the Composite Pattern).

A very basic example of one way to generate a tree of the operations.

I've nested the classes within a single Test class (since I didn't want to faff around with extra files) but it should be simple enough to unbundle).

  • MathNode is an abstract class representing a node in the tree;
  • ElementNode is a sub-class of MathNode representing a number value (and a leaf of the tree);
  • SumNode is a sub-class of MathNode representing an operation;
  • tokenize() iterates through the string finding operations (or the end of the string) and the preceding number and creates the appropriate tokens and appends them to an array.
  • makeTree() iterates through the array of tokens and when the current operation being searched for is found sets the left and right nodes of the tree to be the immediately preceding and succeeding tokens (removing those tokens from the array once added to the tree).
  • Running tokenize() then makeTree() four times, one for each of the / , * , - and then + operations, will build the tree with the single Node left in the array of tokens being the root of the tree.

There is more error checking that can be included and I'm sure the tree building can be made significantly more efficient (and not to require four passes) but, hopefully, this will give you an idea of how to proceed.

The code:

import java.util.ArrayList;

public class Test
{
    public static enum Operation { MULTIPLY, DIVIDE, ADD, SUBTRACT };
    abstract static class MathNode {
        public abstract double calc();
        public abstract String toString();
        public abstract boolean set( final MathNode left, final MathNode right, final Operation op );
    }
    static class ElementNode extends MathNode {
        private final double value;
        public ElementNode( final double v ) {
            this.value = v;
        }
        public double calc() {
            return value;
        }
        public String toString() {
            return Double.toString( value );
        }
        public boolean set( final MathNode left, final MathNode right, final Operation op ){
            return false;
        }
    }
    static class SumNode extends MathNode {
        public MathNode left = null;
        public MathNode right = null;
        public final Operation op;
        public SumNode( final Operation op ){
            this.op = op;
        }
        public boolean set( final MathNode left, final MathNode right, final Operation op ){
            if ( this.op == op )
            {
                this.left = left;
                this.right = right;
                return true;
            }
            return false;
        }
        public double calc() {
            final double l = left  == null ? 0 : left.calc();
            final double r = right == null ? 0 : right.calc();
            switch ( this.op ){
            case MULTIPLY:  return l * r;
            case DIVIDE:    return l / r;
            case SUBTRACT:  return l - r;
            default:        return l + r;
            }
        }
        public String toString(){
            final String l = left  == null?"0":left.toString();
            final String r = right == null?"0":right.toString();
            switch ( this.op ){
            case MULTIPLY:  return "( " + l + " * " + r + " )";
            case DIVIDE:    return "( " + l + " / " + r + " )";
            case SUBTRACT:  return "( " + l + " - " + r + " )";
            default:        return "( " + l + " + " + r + " )";
            }
        }
    }
    public static ArrayList<MathNode> tokenize( final String sum )
    {
        int i = 0,
            p = 0;
        final int l = sum.length();
        final ArrayList<MathNode> tokens = new ArrayList<MathNode>();
        while ( i < l )
        {
            final SumNode sn;
            switch ( sum.charAt(i) ){
            case '*':   sn = new SumNode( Operation.MULTIPLY ); break;
            case '/':   sn = new SumNode( Operation.DIVIDE );       break;
            case '+':   sn = new SumNode( Operation.ADD );      break;
            case '-':   sn = new SumNode( Operation.SUBTRACT ); break;
            default:
                // TODO: Add something to check if number is valid
                ++i; 
                continue;
            }
            // TODO: Add something to check for zero-width numbers 
            final double value = Double.parseDouble( sum.substring( p, i ) );
            p = ++i;
            tokens.add( new ElementNode( value ) );
            tokens.add( sn );
        }
        // TODO: Add something to check for zero-width numbers
        final double value = Double.parseDouble( sum.substring( p ) );
        tokens.add( new ElementNode( value ) );
        return tokens;
    }
    public static void makeTree( final ArrayList<MathNode> tokens, final Operation op ){
        for ( int i = tokens.size() - 2; i >= 1; --i )
        {
            final MathNode node = tokens.get( i );
            if ( node.set( tokens.get(i-1), tokens.get(i+1), op) )
            {
                tokens.remove( i + 1 );
                tokens.remove( i - 1 );
                --i;
            }
        }
    }
    public static void main(final String[] args) {
        final String sum = "23.2-5.2*4.4/2.2+14";
        final ArrayList<MathNode> tokens = tokenize( sum );
        makeTree( tokens, Operation.DIVIDE );
        makeTree( tokens, Operation.MULTIPLY );
        makeTree( tokens, Operation.SUBTRACT );
        makeTree( tokens, Operation.ADD );
        final MathNode sum_tree = tokens.get(0);
        System.out.println( sum_tree + " = " + sum_tree.calc() );
    }
}

Do you really need to scan all the operators, calculate priority, and re-order everything?

What if you just went though all the operators and values, and evaluated only the * and the /

Then go through again and evaluate the + and the -

Might be much easier than what you are trying to do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM