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

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


按照算法逻辑,我们可以将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
   

(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;        }    }}



更多相关文章

  1. [Android]Thread线程入门4--多线程
  2. Android--hw_get_module解析
  3. Android学习探索之Java 8 在Android(安卓)开发中的应用
  4. Android基础_页面布局_RelativeLayout(相对布局)
  5. 同一款Android软件有两样东西是不会变的:包名和数字签名
  6. Android对emoji表情的处理(二)
  7. Android(安卓)Native/Tombstone Crash Log 详细分析
  8. Android(安卓)studio edit view 边框显示,inputType
  9. Android(安卓)自定义数字键盘(一)

随机推荐

  1. android 比较符合android构架,优雅的定义
  2. Android快速开发
  3. Using your own SQLite database in Andr
  4. android 登录判断
  5. android之单选框
  6. Android(安卓)tensorflow图片识别demo
  7. Android——SimpleExpandableListAdapter
  8. Android:View的getLocalVisibleRect()和getG
  9. android 版本跟新之下载
  10. Android(安卓)双缓冲 使用 示例