Android开发——实现Android简易计算器

计算器输入的字串属于中缀表达式,即Infix Expression,例如:2+3*5-6。
然而对于程序来说,要处理这样的表达式比较困难,因为不知道该何时处理表达式中的某个子表达式。因此,需要将这样的表达式转换成后缀表达式(Suffix Expression),然后通过程序逻辑将程序结果计算出来。

下面看其一个转换的例子(取自维基百科):

Android开发——实现Android简易计算器_第1张图片

按照算法逻辑,我们可以将2+3*5-6转换成235*+6-。


在我们处理计算器的表达式时,要考虑其是由数字符号和计算符号组成,然而计算符号又存在一定的优先级。因此,可以维护两个栈分别存储数字符号num_stack和计算符号operator_stack,通过不断的入栈和出栈的操作实现表达式的计算。
下面考虑到实现的是一个简易的计算器,仅考虑输入正数和“+、-、*、/”四个运算。不过为了之后的扩展,也考虑"(、)"两个运算符。
其中,将中缀表达式转后缀表达式的并计算出结果的伪代码如下:
输入:中缀表达式s
    输出:计算结果result
    算法calculateInfixExp(s):
           start 遍历s中所有的字符c,                       
                     如果c = ‘(’,则  str = str +c  until  c = ‘)’;
                     calResult = calculateInfixExp(str);
                     num_stack.push(calResult);

                     如果c为数字符号,则num_stack.push(c);
                     如果c为计算符号,c的优先级小于或等于栈顶计算符号,则
                          start  遍历operator_stack,
                                   计算符号 = operator_stack.pop();
                                   n1 = num_stack.pop();
                                   n2 = num_stack.pop();
                                   num_stack.push(n1 计算符号 n2);
                                    如果 c的next为null,则 operator_stack.push(c);
                            end 遍历operator_stack
          end 遍历s中所有的字符c

核心代码:
(1)布局XML
Android开发——实现Android简易计算器_第2张图片
 


 
 

(2)Activity
public class Calculator extends Activity {

    final String[] buttonStrings = new String[]
            {
                    "7", "8", "9", "+",
                    "4", "5", "6", "-",
                    "1", "2", "3", "*",
                    ".", "0", "=", "/"
            };

    private boolean isOperator(String str) {
        if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/") || str.equals("=")) {
            return true;
        }
        return false;
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_calculator);

        //得到屏幕的size
        Point size = new Point();
        getWindowManager().getDefaultDisplay().getSize(size);
        int oneQuarterWidth = (int) (size.x * 0.25);

        GridLayout gridLayout = (GridLayout) findViewById(R.id.root);

        Button btn = null;
        for (int i = 0; i < buttonStrings.length; ++i) {
            btn = new Button(this);
            btn.setText(buttonStrings[i]);
            btn.setTextSize(40);
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Button button = (Button) view;
                    TextView showView = (TextView) findViewById(R.id.showView);

                    //如果含有等号则输入其他字符时清楚显示数字
                    if (showView.getText().toString().contains("=")) {
                        showView.setText("");
                    }

                    //这里仅实现简单的容错处理:1、首字母不能为计算符号
                    if (showView.getText().toString().isEmpty() && isOperator(button.getText().toString())) {
                        return;
                    }
                    //2、尾字母不能为计算符号
                    if (button.getText().equals("=") && isOperator(String.valueOf(showView.getText().charAt(showView.getText().length() - 1)))) {
                        return;
                    }
                    // 3、不能出现连续的计算符号
                    if (showView.getText().length() > 1 && isOperator(String.valueOf(showView.getText().charAt(showView.getText().length() - 1)))
                            && isOperator(button.getText().toString())) {
                        return;
                    }

                    //处理显示和计算逻辑
                    if (!button.getText().equals("=")) {
                        showView.append(button.getText());
                    } else {
                        showView.setText(showView.getText().toString() + "=" + String.valueOf(CalculatorAlgorithm.calculateInfixExp(showView.getText().toString())));
                    }

                }
            });
            GridLayout.Spec rowSpec = GridLayout.spec(i / 4 + 2);
            GridLayout.Spec colSpec = GridLayout.spec(i % 4);
            GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams(rowSpec, colSpec);
            layoutParams.width = oneQuarterWidth;
            gridLayout.addView(btn, layoutParams);
        }

        //绑定清除屏幕数字方法
        Button clearBtn = (Button) findViewById(R.id.clear);
        clearBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TextView showView = (TextView) findViewById(R.id.showView);
                showView.setText("");
            }
        });

        //绑定回退键方法
        Button backBtn = (Button) findViewById(R.id.back);
        backBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TextView showView = (TextView) findViewById(R.id.showView);
                if(!showView.getText().toString().isEmpty())
                {
                    showView.setText(showView.getText().toString().substring(0,showView.getText().length()-1));
                }
            }
        });

    }
}
(3)算法类
/**
 * Created by ZH on 2014/12/1.
 */
public class CalculatorAlgorithm {
    private static Map operatorPriority = new HashMap();

    static {
        //符号对应的数值越高则优先级越高
        operatorPriority.put("+", 10);
        operatorPriority.put("-", 10);
        operatorPriority.put("*", 20);
        operatorPriority.put("/", 20);
    }

    /**
     * 中缀表达式转后缀表达式的并计算出结果
     *
     * @param infixExp
     * @return
     */
    public static Double calculateInfixExp(String infixExp) {
        if (null == infixExp || infixExp.isEmpty()) {
            return null;
        }

        char c;
        int subStart = 0;
        StringBuilder numBuf = new StringBuilder();
        //存放数字的栈
        Stack numStack = new Stack();
        //存放计算符的栈  1-0.5*(3.5-1.5)-5.3
        Stack operatorStack = new Stack();
        for (int i = 0; i < infixExp.length(); ) {
            c = infixExp.charAt(i);
            //先处理含括号的场景
            if ('(' == c) {
                subStart = infixExp.indexOf(')', i);
                numStack.push(calculateInfixExp(infixExp.substring(i + 1, subStart)));
                i = subStart + 1;
                continue;
            }

            //如果是数字
            if (String.valueOf(c).matches("[0-9.]")) {
                numBuf.append(c);
                //最后一个字符若是数字则直接入栈
                if (infixExp.length() == (i + 1)) {
                    numStack.push(Double.valueOf(numBuf.toString()));
                }
            } else
            //如果是计算符号
            {
                //若前一个字符为右括号,则当前字符肯定为计算符号,因此不入数字栈
                if (')' != infixExp.charAt(i - 1)) {
                    numStack.push(Double.valueOf(numBuf.toString()));
                    numBuf = new StringBuilder();
                }

                //当前的优先级小于或等于栈顶的
                if (!operatorStack.isEmpty() && operatorPriority.get(String.valueOf(c)) < operatorPriority.get(operatorStack.peek().toString())) {
                    popOperation(numStack, operatorStack);
                }
                operatorStack.push(c);
            }
            //最后一个字符
            if (infixExp.length() == (i + 1)) {
                popOperation(numStack, operatorStack);
            }
            ++i;
        }
        return numStack.pop();
    }

    /**
     * 处理数字和计算符号进行计算并将结果入栈
     * @param numStack
     * @param operatorStack
     */
    private static void popOperation(Stack numStack, Stack operatorStack) {
        char top;
        double num1 = 0;
        double num2 = 0;
        while (!operatorStack.isEmpty()) {
            top = operatorStack.pop();
            num1 = numStack.pop();
            num2 = numStack.pop();
            numStack.push(calculate(top, num2, num1));

        }
    }

    /**
     * 根据计算符号oper对n1和n2进行计算,并返回double型结果
     * @param oper
     * @param n1
     * @param n2
     * @return
     */
    private static double calculate(char oper, double n1, double n2) {
        switch (oper) {
            case '+':
                return n1 + n2;
            case '-':
                return n1 - n2;
            case '*':
                return n1 * n2;
            case '/':
                if (0 == n2) {
                    return 0;
                }
                return n1 / n2;
            default:
                return 0;
        }
    }

}



你可能感兴趣的:(Android,Android,计算器,算法,中缀表达式,学习)