不懂就问,关于js四则运算

实现能够计算算式字符串,不能通过eval,网上找了一个利用二叉树的方式,然后恶补了下二叉树,但是在看下面的代码时依然无法很多困惑,这个二叉树怎么建立起来的?哪里体现了二叉树?望路过的各位大神指点下(尽可能详细些,谢谢)。

function CalcNode(expr){

    var exprArr = expr.split("");
    var length  = exprArr.length;
    var index   = 0;

    this.left = null;
    this.right = null;

    if(length>1){

        for(i=length-1; i>=0; i--){   
            //这个地方的循环的目的是什么?
            //带进算式字符,看了下,是获取加减或乘除的位置

            if(exprArr[i] === "*" || exprArr[i] === "/"){
                index = i;
            }else if(exprArr[i] === "+" || exprArr[i] === "-"){
                index = i;
                break;
            }

        }

        var leftArr = [];
        var rightArr = [];
        for(var i=0; i<index;i++){
         
            leftArr.push(exprArr[i]);
            
        }
        
        for(var i=index+1; i<length; i++){
            rightArr.push(exprArr[i]);
        }
        
       // 这上面的两个for循环根据下标分割算式字符,为什么这么做?
       //它是怎么考虑到先乘除后加减的?
        
        var left = new CalcNode(leftArr.join(""));
        var right = new CalcNode(rightArr.join(""));


        this.left = left;
        this.right = right;
    }

    this.value = exprArr[index]; 

}

CalcNode.prototype.calculate = function(){
    var res = 0;

    if(this.left=== null && this.right === null){
        res = parseInt(this.value);
    }else{

        var leftValue = this.left.calculate();
        var rightValue = this.right.calculate();

        switch(this.value){
            case "*":
                res += leftValue*rightValue;
                break;
            case "/":
                res += leftValue/rightValue;
                break;
            case "+":
                res += leftValue+rightValue;
                break;
            case "-":
                res += leftValue - rightValue;
            default:
                break;
        }
    }

    return res;
}

var cnode = new CalcNode("1+2*3+4");
阅读 4.4k
3 个回答

我们用你代码中的1+2*3+4举例,回答你的两个问题

二叉树是怎么建立起来的?

  • 得到表达式先被split,得到['1', '+', '2', '*', '3', '+', '4']
  • 遍历数组,寻找离尾最近的+或-,并通过leftArr和rightArr存放,符号两边的表达式,得到leftArr ['1', '+', '2', '*', '3'],rightArr['4'],并得到运算符+
  • 递归还有运算符的leftArr和rightArr,就得到了一棵二叉树,对应图就是这样的

图片描述

打印出的数据结构与上图完全一致
clipboard.png

哪里体现了二叉树?

看了上面两张图,你应该自己知道了吧 :)

上面大佬配图说明了这个树的样子,已经很直观的体现了最终的结果了,不过我觉得有个点(就是怎么做到先乘除后加减的)没指的很具体,我就再啰嗦一下。
请看代码中如下部分:

 for(i=length-1; i>=0; i--){   
            //这个地方的循环的目的是什么?
            //带进算式字符,看了下,是获取加减或乘除的位置

            if(exprArr[i] === "*" || exprArr[i] === "/"){
                index = i; 
            //index会存储*/的位置,但是本循环还没有结束,还会继续遍历剩下的字符,
            //index的值还有可能随着循环而改变,所以*/的拆分都是每一个左字符串和右字符串最后进行拆分,
            // 以达到将*/操作拆分到所有+-的叶子方向节点
            }else if(exprArr[i] === "+" || exprArr[i] === "-"){
                index = i;
                break; // 体会一下这个break是做什么呢?
                // 1. 一旦遇到+和-字符,循环立马跳出,不继续循环,index就锁定为+和-的位置
            }
        }

还可以用Function,或者Antlr

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题