zoukankan      html  css  js  c++  java
  • Flex版本的基于栈的表达式计算器

        /**
         * 表达式计算器,输入数学表达式的字符串,输出计算结果的数值
         * 1.扫描表达式,将运算符与运算数分别入栈,
         * 2.运算符入栈前先与上一个运算符进行优先级比较,如果当前运算符优先级低于或等于前一个运算符,
         * 则将前一个运算符和对应的运算数出栈运算,否则运算符直接入栈
         * @author lijy
         */
        public class ExpressionCaculator
        {        
            /**
             * 运算数栈
             * */
            private var numberStack:Array;
            
            /**
             * 运算符栈
             * */
            private var operatorStack:Array;
            
            /**
             * 构造函数
             */
            public function ExpressionCaculator(){}
            
            /**
             * 表达式计算器
             * @expression 表达式
             * @return 计算结果,NaN表示格式错误或存在不支持的运算符
             * */
            public function caculate(expression:String):Number{
                
                //去除空格
                var arr:Array = expression.split(' ');
                expression = '';
                for each(var item:String in arr){
                    if(item!=' ')expression+=item;
                }
                
                //初始化栈
                numberStack = new Array();
                operatorStack = new Array();
                
                //遍历表达式
                for(var i:int=0; i<expression.length; i++){
                    var index:int = getNextNumberEndIndex(expression,i);
                    if(index>i){
                        //获取运算数
                        var data:Number = Number(expression.substr(i,index-i));
                        if(isNaN(data)){
                            //表达式有误返回NaN
                            return NaN;
                        }else{
                            //运算数入栈
                            numberStack.push(data);
                            i=index-1;
                        }
                    }else{
                        //获取运算符,并调用出栈运算循环
                        var nextOperator:String = expression.substr(i,1);                    
                        var success:Boolean = this.calculateLoop(nextOperator)
                        if(!success){
                            //运算过程中出现不支持的操作符
                            return NaN;
                        }else if(nextOperator!=')'){
                            //操作符入栈,右括号除外
                            operatorStack.push(nextOperator);
                        }
                    }
                }
                
                //最后调用出栈运算循环,计算还没有算完的部分
                var success:Boolean = this.calculateLoop()
                if(!success){
                    //运算过程中出现不支持的操作符
                    return NaN;
                }else{
                    //返回计算结果
                    return numberStack[0];
                }
            }
            
            /**
             * 出栈运算循环:
             * 循环出栈之前的运算符与下一个即将入栈的运算符做优先级对比,
             * 若优先级高于下一个则进行计算,若为括号则根据情况做括号合并或跳出计算
             * @nextOperator 下一个即将入栈的运算符,用于跟之前的运算符做优先级对比或括号消除
             * @return 计算是否成功,如果存在不支持的运算符将返回NaN
             * */
            private function calculateLoop(nextOperator:String=')'):Boolean{
                //返回结果初始值:是否存在不支持的运算符
                var result:Boolean=true;
                //获取下一个运算符的优先级
                var nextPriority:Number = getOperatorPriority(nextOperator);
                //进入运算循环
                while(operatorStack.length>0){
                    var lastOperator:String = operatorStack[operatorStack.length-1];
                    var lastPriority:Number = getOperatorPriority(lastOperator);
                    if(isNaN(lastPriority) || isNaN(nextPriority)){
                        //存在不支持的运算符
                        result = false;
                        break;
                    }
                    if(nextPriority > lastPriority){
                        //优先级大于之前的运算符则不运算,跳出循环
                        result = true;
                        break;
                    }else if(lastOperator=='('){
                        //如果上一个运算符是左括号:
                        //1.下一个运算符是右括号,那么左右括号抵消,运算符出站并跳出运算循环
                        //2.下一个运算符不是右括号,那么左括号保留,跳出运算循环
                        if(nextOperator==')')operatorStack.pop();
                        result = true;
                        break;
                    }else{ 
                        //其他情况出站运算并循环
                        result = popAndCalculate();
                        if(result==false){
                            break;
                        }
                    }
                }
                return result;
            }
            
            /**
             * 出栈最后一个运算符和对应的运算数进行运算,将运算结果入栈
             * @return 运算异常返回false,正常返回true
             * */
            private function popAndCalculate():Boolean{
                if(numberStack.length<2 || operatorStack.length<1){
                    //至少要有两个运算数和一个运算符
                    return false;
                }else{
                    var lastOperator:String = operatorStack.pop() as String;
                    var num1:Number = numberStack.pop() as Number;
                    var num2:Number = numberStack.pop() as Number;
                    switch(lastOperator){
                        case '*':
                            numberStack.push(num2*num1);
                            break;
                        case '/':
                            numberStack.push(num2/num1);
                            break;
                        case '+':
                            numberStack.push(num2+num1);
                            break;
                        case '-':
                            numberStack.push(num2-num1);
                            break;
                    }
                    return true;
                }
            }
            
            /**
             * 从指定下标位置开始获取下一个运算数结束的下标位置,注意判断减号和负号
             * @expression 表达式
             * @startIndex 判断的起始下标位置
             * @return 下一个运算数结束的下标位置,若返回值与startIndex相等说明下一个字符是操作符不是运算数
             * */
            private static function getNextNumberEndIndex(expression:String, startIndex:int):int{
                var i:int=startIndex;
                //判断减号和负号,表达式的第一个字符或者左括号前的第一个字符如果为-,则判定为负号,否则为减号
                if(expression.charAt(i)=='-'){
                    if(i==0 || expression.charAt(i-1)=='('){
                        i++;
                    }else{
                        return i;
                    }
                }
                //遍历数字和小数点
                for(i; i<expression.length; i++){
                    var ascii:Number = expression.charCodeAt(i);
                    if((ascii>=48&&ascii<=57) || ascii==46){
                        continue;
                    }else{
                        return i;
                    }
                }
                return i;
            }
            
            /**
             * 获取运算符优先级
             * @operator 运算符
             * @return 优先级
             * */
            private static function getOperatorPriority(operator:String):Number{
                switch(operator){
                    case '(':
                        return 3;
                    case '*':
                    case '/':
                        return 2;
                    case '+':
                    case '-':
                        return 1;
                    case ')':
                        return 0;
                    default:
                        return NaN;
                }
            }
    
        }
  • 相关阅读:
    分母为0一定会抛异常吗?
    [译]Zookeeper的优点与局限性
    明明有class为什么还是报ClassNotFoundException?
    广告倒排索引架构与优化
    KafkaProducer源码分析
    Kafka服务端之网络连接源码分析
    Sublime常用快捷键
    sublime主题设置
    Sublime前端插件
    安装软件,更新软件,删除软件
  • 原文地址:https://www.cnblogs.com/ArtofDesign/p/5072228.html
Copyright © 2011-2022 走看看