四则运算java实现

实现四则运算一般都是利用自动机理论,对字符逐个读取,然后判断应处的状态,最后将自动机优化实现程序。
只是突然想起有另一种计算方式,不知是否有前辈已经写出,只是怕自己会突然忘记,因此记录下来,供以后使用。

对于一个简单的加减法运算来说(抛去有正数或负数的存在,因为负号与减号容易混淆),符号总是比数据少一个,例如

/*对于一个四则元算字符串:A+B-C 来说,若是以符号为分隔将数和运算符分开,以向量来存储,那么结果为:*/
number:A B C
operator:+ -

此时怎么做应该很清楚了吧,对向量operator取第一个成员,此时得到了一个“+”号,那么只要取number中的两个数,然后让两个数相加(假如说得到了D,此时要根据运算符号来操作两个数),放入number第一个成员位置,再移除operator第一个成员,移除number第二个成员,例如:

number.setElementAt(number.firstElement()+number.get(1),0);
number.remove(1);
operator.remove(0);
/*此时两个向量中剩下的内容是什么:
number:D C
operator:-

看到了吧,继续上次的运算,直到operator中为空,此时number中必定还剩下一个成员,那就是最终的结果,下面贴出完整步骤:

while(!operator.isEmpty()){
    char ch=operator.firstElement();
    if(ch=='+'){
        number.setElementAt(number.firstElement()+number.get(1),0);
    }else if(ch=='-'){
        number.setElementAt(number.firstElement()-number.get(1),0);
    }
    number.remove(1);
    operator.remove(0);
}
return number.firstElement().toString();

看到这大家估计会嗤之以鼻,说这玩意早几百年都懂了,还写这干啥,当然,没有哪个运算只有加减法,还不能带符号的,接下来就进行加减法的进阶——乘除法。
别笑!
容我先贴出完整的程序来,然后再分析:

protected static String account_second(Vector<Float> number,Vector<Character> operator){
/*对于静态方法account_second来说,呃,这个函数名字很让我纠结,不过不想去改代码了,number代表字符串分割后数的集合,operator相当于分割后操作数的集合*/
    try {
        int k=0;
        while(operator.size()>k){
            char ch=operator.get(k);
            if(operator.get(k)=='*'){
                number.setElementAt(number.get(k) * number.get(k+1), k);
            }
            else if(ch=='%'){
                number.setElementAt(number.get(k)%number.get(k+1),k);
            }
            else if(ch=='/'){
                number.setElementAt(number.get(k)/number.get(k+1),k);
            }
            //碰到“高级”运算直接操作,此时都是二目运算符,因此不会有问题。
            else if(ch=='+'||ch=='-') {
                k++;
                continue;
            }
            //碰到“低级”运算符要让位,这里只进行高级运算。
            number.remove(k+1);
            operator.remove(k);
        }
        while(!operator.isEmpty()){
            char ch=operator.firstElement();
            if(ch=='+'){
                number.setElementAt(number.firstElement()+number.get(1),0);
            }else if(ch=='-'){
                number.setElementAt(number.firstElement()-number.get(1),0);
            }
            number.remove(1);
            operator.remove(0);
        }
        return number.firstElement().toString();
        //这部分不解释,就是之前贴过的代码。
    } catch(Exception e){
        return "input error";
    }
    //我非常认真的提醒大家,try catch是精髓,它可以保证:
    //咳,保证程序不小心有问题也不会检查不出来。
}

看到这你估计就明白为什么我先贴代码了,没错,按照四则运算的规矩,乘除先行,这里就是先进行了乘除法的运算,直到operator中没有乘除取模为止,若是中间遇到加减符号,直接隔过就行。怎么样,简单吧。
或许对此你仍然不屑一顾,没有括号的四则运算能叫运算么?
对,你说的对,这程序若到此为止,我也不好意思贴出来了,简直是打我老师的脸。下面进行乘除进阶——括号运算。

其实这部分也没有什么大问题,只是我思维偏向于混乱,因此这部分的代码很垃圾,不过总算把功能实现了,如果谁有更为精准简洁的代码,请务必不要告诉我,我怕打脸。
好了,下面还是贴代码:

public static String account(String string) {

    boolean flag=true;
    try {
        Vector<Float> number=new Vector<Float>();
        Vector<Character> operator=new Vector<Character>();
        //定义存储运算符和操作数的向量。
        String strings[] = string.split("\\+|-|\\*|%|/|\\(|\\)");/*此处是将四则运算字符串以操作符为界限进行分割,切记加号乘号以及括号匹配时候是需要转义的,具体内容请自学正则表达式。“+,-,*,/,%,(,)”*/
        for (String i : strings) {
            if(!i.equals("")) {
                number.add(Float.parseFloat(i));
            }
        }
        //将分割后得到的字符串转化为float类型存在number里。
        char chars[] = string.toCharArray();
        int num[]=new int[number.size()];
        int k=0;
        for (Character i : chars) {
            if (i == '+' || i == '-' || i == '*' || i == '/' || i == '%') {
                operator.add(i);
                k++;
            }else if(i=='('){
                num[k]++;
            }else if(i==')'){
                num[k]--;
            }
        }
        /*这部分估计你傻眼了吧,其实很简单,首先对字符串数组化得到操作符,这过程中肯定会碰到括号,因此新建一个与number对应的数组num,里面记录括号的位置,碰到一个左括号“(”,就让对应number所在位置的num加一,碰到一个“)”,就让对应number位置的num减一,因为括号的匹配性,查找完之后,num数组中所有数加起来应该还是零。*/
        /*不知你发现没有,此时此刻operator中数据个数还是比number中数据个数少一,一定要记住,这才是这种算法存在的基础,要不然天晓得自己应该操作哪个数*/
        flag=true;
        while(flag){
            for(int i=0;i<num.length;i++){
                if(num[i]<0){
                    num[i]+=1;//左括号值为1,右括号值为-1;

                    flag=!flag;
                    for(int j=i-1;j>=0;j--){
                        if(num[j]>0){
                            num[j]-=1;
                            num[j]=num[j]+num[i];
                            if(i+1!=num.length){
                                for(int t=i+1;t<num.length;t++){
                                    num[t-(i-j)]=num[t];
                                }
                            }
                            for(int t=num.length-(i-j);t<num.length;t++){
                                num[t]=0;
                            }//将数组中括号匹配到位

                            Vector<Float> new_number=new Vector<Float>();
                            Vector<Character> new_operator=new Vector<Character>();
                            for(int p=j;p<=i-1;p++){
                                new_number.add(number.get(p));
                                new_operator.add(operator.get(p));
                            }
                            new_number.add(number.get(i));

                            String str=account_second(new_number,new_operator);
                            if(!str.equals("input error")){
                                number.setElementAt(Float.parseFloat(str),i);
                            }
                            else{
                                return "input error";
                            }
                            //将括号中数与符号单独提出,新建对应的向量,然后利用second-account求出值,再将新值
                            //放入原来向量,直到没有括号为止。

                            for(int m=j;m<i;i--){
                                number.remove(j);
                                operator.remove(j);
                            }
                            j=-1;i=num.length;
                        }
                    }
                }
            }
            flag=!flag;
        }
        return account_second(number,operator);
    } catch (Exception e) {
        return "error";
    }
}
后面有很长一部分没有注释,实在是我的算法太恶心,我自己都不好意思说明白,我只说一下大致要实现的功能:
讲解过的部分经过操作应该会得到三个集合,operator,numbernum;
对于一个运算式  (7+(5-3))*2  来说,这三部分内容分别如下:
number7    5    3     2
num1    1    -2    0
operator:+  -   *
就是这样,括号的位置记录在与之接近的操作数上,且不会有单个括号同时接近两个操作数。
根据四则运算法则,有括号先计算括号里面的内容,有多个括号呢?那就应该先从左到右查找第一个右括号“)”,然后从第一个右括号开始,向左查找第一个左括号“(”,里面的部分就是你要先计算的。
括号里面的内容肯定不含括号了,那就调用使用之前写的计算乘除加减的方法,将得到的数值写入number中,然后将括号位置对应的num中数字变化,
还要移除已经使用过的operator中的操作符,移除运算过的number中的操作数,直到num中数字全为零,最后会剩下没有括号干扰的number和operator,这下就好办了吧。

好了以上就是四则运算的java实现,是不是有种恶心的感觉?没关系,我们接着看,正数和负数的问题还没解决呢。
好吧,其实最后的问题很好解决,在开始分割字符串之前检查一下就好了,如果发现有减号出现并且该减号左端不是数字,那么~~~那么就在减号前面加个零“0”好了,不要尝试去直接修改operator中对应的值,那样会很蠢。这样得到的字符串不就很规范了么。自己写的实现代码如下:

    public static String addChar(String string,int i,boolean b,String str){
        if(b){
            String frontPart = string.substring(0, i);
            String backPart = string.substring(i);
            string = frontPart + str + backPart;
        }else{
            String frontPart=string.substring(0,i+1);
            String backPart = string.substring(i+1);
            string=frontPart+str+backPart;
        }
        return string;
    }

    while(flag) {
        flag=!flag;
        string=string.replace(" ","");
        char ch[] = string.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            if(ch[i] == '-' || ch[i] == '+') {
                if (i == 0 || (i != 0 && ch[i - 1] == '(')) {
                    string=addChar(string,i,true,"0");
                    flag =!flag;
                    break;
                }
                if(i==ch.length-1||(i!=ch.length-1&&ch[i+1]==')')){
                    string=addChar(string,i,false,"0");
                    flag=!flag;
                    break;
                }
            }
            if(i!=0&&ch[i]=='('&&'0'<=ch[i-1]&&ch[i-1]<='9'){
                string=addChar(string,i,true,"*");
                flag=!flag;
                break;
            }
            if(i!=ch.length-1&&ch[i]==')'&&'0'<=ch[i+1]&&ch[i+1]<='9'){
                string=addChar(string,i,false,"*");
                flag=!flag;
                break;
            }
        }
    }

这段代码不单单是解决了负号正号存在的问题,还可以去除字符串空格,以及很多的错误输入问题,如”1+3+”,这明显是输入错误,而我们可以将其处理,比如变成“1+3+0”,或者“1+3”;还有省略乘号的问题,如“(2+7)4”,我们将其变为“(2+7)*4”,这样是不是就人性化多了呢?
当然,这种想法还可以继续延伸,比如阶乘符号怎么算,次方怎么算,根号怎么算,这些都可以根据运算优先级来得到解决。

好了,终于到结尾了,想吐的同学可以吐了,这是我之前自己鼓捣安卓计算器的时候整的,最后时候计算器也能用,因此代码应该没问题,但不排除我粘贴复制出手抖出错,整个计算过程完整代码附上:


import java.util.*;
/**
 * Created by wang on 2015/10/6.
 */
public class Account{
    public static String addChar(String string,int i,boolean b,String str){
        if(b){
            String frontPart = string.substring(0, i);
            String backPart = string.substring(i);
            string = frontPart + str + backPart;
        }else{
            String frontPart=string.substring(0,i+1);
            String backPart = string.substring(i+1);
            string=frontPart+str+backPart;
        }
        return string;
    }
public static String account(String string) {

    boolean flag=true;
    while(flag) {
        flag=!flag;
        string=string.replace(" ","");
        char ch[] = string.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            if(ch[i] == '-' || ch[i] == '+') {
                if (i == 0 || (i != 0 && ch[i - 1] == '(')) {
                    string=addChar(string,i,true,"0");
                    flag =!flag;
                    break;
                }
                if(i==ch.length-1||(i!=ch.length-1&&ch[i+1]==')')){
                    string=addChar(string,i,false,"0");
                    flag=!flag;
                    break;
                }
            }
            if(i!=0&&ch[i]=='('&&'0'<=ch[i-1]&&ch[i-1]<='9'){
                string=addChar(string,i,true,"*");
                flag=!flag;
                break;
            }
            if(i!=ch.length-1&&ch[i]==')'&&'0'<=ch[i+1]&&ch[i+1]<='9'){
                string=addChar(string,i,false,"*");
                flag=!flag;
                break;
            }
        }
    }
    try {
        Vector<Float> number=new Vector<Float>();
        Vector<Character> operator=new Vector<Character>();
        String strings[] = string.split("\\+|-|\\*|%|/|c|s|\\(|\\)");
        for (String i : strings) {
            if(!i.equals("")) {
                number.add(Float.parseFloat(i));
            }
        }
        char chars[] = string.toCharArray();
        int num[]=new int[number.size()];
        int k=0;
        for (Character i : chars) {
            if (i == '+' || i == '-' || i == '*' || i == '/' || i == '%') {
                operator.add(i);
                k++;
            }else if(i=='('){
                num[k]++;
            }else if(i==')'){
                num[k]--;
            }
        }

        flag=true;
        while(flag){
            for(int i=0;i<num.length;i++){
                if(num[i]<0){
                    num[i]+=1;//左括号值为1,右括号值为-1;

                    flag=!flag;
                    for(int j=i-1;j>=0;j--){
                        if(num[j]>0){
                            num[j]-=1;

                            num[j]=num[j]+num[i];
                            if(i+1!=num.length){
                                for(int t=i+1;t<num.length;t++){
                                    num[t-(i-j)]=num[t];
                                }
                            }
                            for(int t=num.length-(i-j);t<num.length;t++){
                                num[t]=0;
                            }//将数组中括号匹配到位

                            Vector<Float> new_number=new Vector<Float>();
                            Vector<Character> new_operator=new Vector<Character>();
                            for(int p=j;p<=i-1;p++){
                                new_number.add(number.get(p));
                                new_operator.add(operator.get(p));
                            }
                            new_number.add(number.get(i));

                            String str=account_second(new_number,new_operator);
                            if(!str.equals("input error")){
                                number.setElementAt(Float.parseFloat(str),i);
                            }
                            else{
                                return "input error";
                            }
                            //将括号中数与符号单独提出,新建对应的向量,然后利用second-account求出值,再将新值
                            //放入原来向量,直到没有括号为止。

                            for(int m=j;m<i;i--){
                                number.remove(j);
                                operator.remove(j);
                            }
                            j=-1;i=num.length;
                        }
                    }
                }
            }
            flag=!flag;
        }
        return account_second(number,operator);
    } catch (Exception e) {
        return "error";
    }
}

    protected static String account_second(Vector<Float> number,Vector<Character> operator){
        try {
            int k=0;
            while(operator.size()>k){
                char ch=operator.get(k);
                if(operator.get(k)=='*'){
                    number.setElementAt(number.get(k) * number.get(k+1), k);
                }
                else if(ch=='%'){
                    number.setElementAt(number.get(k)%number.get(k+1),k);
                }
                else if(ch=='/'){
                    number.setElementAt(number.get(k)/number.get(k+1),k);
                }
                else if(ch=='+'||ch=='-') {
                    k++;
                    continue;
                }
                number.remove(k+1);
                operator.remove(k);
            }
            while(!operator.isEmpty()){
                char ch=operator.firstElement();
                if(ch=='+'){
                    number.setElementAt(number.firstElement()+number.get(1),0);
                }else if(ch=='-'){
                    number.setElementAt(number.firstElement()-number.get(1),0);
                }
                number.remove(1);
                operator.remove(0);
            }
            return number.firstElement().toString();
        } catch(Exception e){
            return "input error";
        }
    }
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值