博主q q 656358805 欢迎线上交流!

以下两图是计算器的结果展示:

                                                         

好了,那么今天我们来讲一下安卓计算器的简单实现,对于广大愁于编程的初学者大学生来说,自己制作一个计算器的作业会非常难,但是不要害怕,编程本来就很难,智商跟不上很正常,这不!博主所幸为您提供一个解决当务之急渠道,那么就正式开始今天的学习。

这里我们对于计算器界面的设计就略讲了,因为如果读者用android studio做的话界面布局是很简单的,只需用一个表格布局;而用eclipse做的话,就要采用java的swing技术来做界面,用的就是swing中的GridLayout布局管理器,不过出于创新,读者可以试着设计自己的布局方式,那么计算器的界面我就扯这么多了。

下面我要着重讲一下计算器的内核,也就是算法。


使用java呢计算中的大部分基础计算是直接调用java的函数就可以了,比如三角函数,就直接使用java里的Math.sin(),Math.cos(),Math.tan()就可以实现了,这里建议把每一个基本计算放入一个类中,或者是把所有的基本计算类放在一个计算类中,便于编写和阅读。

现在我们讲一下第一个类,也就是计算器的主界面类:MainActivity

在这个类里,我定义了如下的变量。

display:计算器的文本输入和显示框,每当用户输入表达式或删除表达式会在这个文本框中显示。

sign:承装符号的容器

number:承装数字的容器

若干button: 是计算器上的按钮们

private static TextView display;
private Button back,clear,plus,sub,mul,div,leftR,rightR,PI,e,point,equal,one,two,three,four,five,six,seven,eight,nine,zero,sin,cos,tan,pow,Log,ln,design,star;static ArrayList<Character> sign=new ArrayList<Character>();
static ArrayList<Double> number=new ArrayList<Double>();

在这里我们要做的第一步已经完成,就是数据的定义,其次我们要把这些button都加上监听器,以实现用户点击按钮时会出现不同的功能效果,加监听器非常简单就不讲了。(注意,在加玩监听器时最好跑一遍代码,试试点击事件是否正确处理,若是处理正确那么就开始我们的表达式处理阶段,也就是算法的核心部分)

在讲核心算法之前我先说一下,可能读者听说过用正则表达式或者各种各样的字符串处理方法来处理输入的字符串,笔者并没有采用这些方式,以下所讲的处理方法是笔者自己想出来的,所以就效率来讲不一定赶得上某些字符处理方法,但是再怎么说也是原创! 我还是把这种算法记录下来,和读者相互交流一下。


刚才读者在加监听器的时候应该发现了一个问题,就是点击等号的时候应该处理什么样的点击事件呢? 那么问题来了,用户所输入的表达式不一定合法,也不一定带有什么样的计算,带括号,或不带括号,我们究竟要怎么做才能知道用户的输入形式呢? 不妨先想一下,如果计算器规定了输入不能带括号,那么就只能计算无括号混合运算,也就是说在用户输入合法的前提下,我们只需判断用户的输入带不带有括号,从而确定基本计算的优先级是否被改变,那么也就是说,如果用户没有输入括号,那就意味着乘除先于加减算。

好了,说了一大堆屁话我们终于清楚了一点——就是我们需要判断表达式中有没有括号。

那么现在我们来考虑一件事,一个表达式非常长,我们要用什么方式得知到底以什么样的顺序来计算一个表达式呢? 笔者给出的方法,首先将输入的表达式切分成众多个数和符号,数字加入到number容器中,符号加入到sign容器中

举个例子: 将(3+2)*5-1这个表达式切分,则sign中应该是‘(’,‘+’,‘)’,‘*’,‘-’ 而number中应该是‘3’,‘2’,‘5’,‘1’

处理切分的时候很容易,但是需要注意的两个问题,当用户输入浮点数时,如:3.25  这个时候3.25是一个数,注意字符的处理,不要把3.25分成3和25了;其次另一个问题是输入一个负数的时候,不能把负号看成减号存入sign,而是连带数字整体存入number,如:输入-3.5,则number中加入的是-3.5,而不是3.5。

下面这段代码就是输入表达式的切分和装入:

boolean isleftR=false;      //这个布尔值表示上一个被扫描的字符是不是左括号
int leftbound=0,rightbound; //leftbound表示要存入容器数据的左边界,rightbound则是有边界,比如3.56左边界指向3,有边界指向6,而单个字符则是左右边界相等
for(int i=0;i<processString.length();i++){          //扫描整个表达式
    if(processString.charAt(i)=='('){            //遇到左括号就将其加入sign,设置isleftR为truesign.add(processString.charAt(i));isleftR=true;

    }else if(processString.charAt(i)==')'||processString.charAt(i)=='+'||processString.charAt(i)=='*'||processString.charAt(i)=='/'){                                                          //如果是右括号,加,乘,除就直接加入sign,重置isleftRsign.add(processString.charAt(i));isleftR=false;

    }else if(processString.charAt(i)=='-'&&!isleftR&&i!=0){R          //减号比较特殊,如果减号不是表达式的第一个符号,而且上一个字符不是左括号,则表示这个减号是运算的减号,否则是负号sign.add(processString.charAt(i));isleftR=false;

    }else if (processString.charAt(i)=='-'&&(isleftR||i==0)){  //负号的话我们要加进number的就不只是一个字符了,我们要加进负号连同它后面的数字,所以我们这里使用预先定义的左右边界,下面if的条件表示有边界选定的规则if(i==0){leftbound = i+1;for (rightbound = leftbound; rightbound < processString.length(); rightbound++) {if (processString.charAt(rightbound) == '(' || processString.charAt(rightbound) == ')' || processString.charAt(rightbound) == '+' || processString.charAt(rightbound) == '-' || processString.charAt(rightbound) == '*' || processString.charAt(rightbound) == '/') {number.add(Double.parseDouble(processString.substring(leftbound-1, rightbound)));break;}}if (rightbound == processString.length()) {         //如果有边界到了表达式的总长度处还没有确定,则视为最后一个字符为有边界number.add(Double.parseDouble(processString.substring(leftbound-1, rightbound - 1) + processString.charAt(processString.length() - 1)));}isleftR = false;i = rightbound - 1;

        }else {leftbound = i+1;for (rightbound = leftbound; rightbound < processString.length(); rightbound++) {if (processString.charAt(rightbound) == '(' || processString.charAt(rightbound) == ')' || processString.charAt(rightbound) == '+' || processString.charAt(rightbound) == '-' || processString.charAt(rightbound) == '*' || processString.charAt(rightbound) == '/') {number.add(Double.parseDouble(processString.substring(leftbound-1, rightbound)));break;}}if (rightbound == processString.length()) {number.add(Double.parseDouble(processString.substring(leftbound-1, rightbound - 1) + processString.charAt(processString.length() - 1)));}isleftR = false;i = rightbound - 1;
        }}else if((processString.charAt(i)>='0')&&(processString.charAt(i)<='9')){    //如果是数字的话,判断方式同负号一样leftbound=i;for(rightbound=leftbound;rightbound<processString.length();rightbound++){if(processString.charAt(rightbound)=='('||processString.charAt(rightbound)==')'||processString.charAt(rightbound)=='+'||processString.charAt(rightbound)=='-'||processString.charAt(rightbound)=='*'||processString.charAt(rightbound)=='/'){number.add(Double.parseDouble(processString.substring(leftbound,rightbound)));break;}

        }if(rightbound==processString.length()){number.add(Double.parseDouble(processString.substring(leftbound,rightbound-1)+processString.charAt(processString.length()-1)));}isleftR=false;i=rightbound-1;

    }else{        //输入其它非法符号则表达式错误Toast.makeText(MainActivity,"计算表达式输入错误!",Toast.LENGTH_LONG).show();}
}

以上是表达式的切分,到现在sign和number容器应该已经装满相应的数据了,然后我们就要以一定的顺序来计算这些数据了,也就是在sign和number这两个容器之间寻找一种规则,此处我们考虑先计算不带括号的表达式,再添加一个定位括号的算法进而完成带括号表达式的计算,所以下面介绍一下不带括号表达式的算法,例如: 输入3*5+2-4 , 结果应该是13.

代码实现如下:

参数解释:a,b为sign和number,length是sign长度,start和startN是指针用于操作容器,数据结构如上图所示
public static double compute_withoutR(ArrayList<Character> a,int start,int length,ArrayList<Double> b,int startN)
{int beginvalue=start;int count=0; //count计数已经算过的符号数for(int i=start;beginvalue<start+length;beginvalue++)         //从头扫描符号容器,因为没有括号,所以先算乘除后算加减{
        if(a.get(i).equals('*')||a.get(i).equals('/')){              //这里我们只讲解乘号,因为后面的判定运算都相似if(a.get(i).equals('*')) {double temp = mul(b.get(startN+i-start),b.get(startN+i-start+1));  //读者不妨对应上面的数据结构看一下这规律,如果第i
个符号是乘号,那么这个乘号所关系的两个乘数,其中一个必定是number的第startN+i-start个数字,另一个是第 startN+i-start+1个数字。

                b.remove(startN+i-start);  //每计算完一次,都要把这次计算的两个数从number中移除,符号也要移除b.remove(startN+i-start);b.add(startN+i-start,temp);//将本次运算结果加入number
                a.remove(i);
                count++;       }else{double temp = div(b.get(startN+i-start),b.get(startN+i-start+1));

                b.remove(startN+i-start);b.remove(startN+i-start);b.add(startN+i-start,temp);

                a.remove(i);
                count++;}}else {
            i++;}}beginvalue=start;for(int i=start;beginvalue<start+length-count;beginvalue++){  //计算剩余符号if(a.get(i).equals('+')||a.get(i).equals('-')){if(a.get(i).equals('+')) {double temp = Plus.plus(b.get(startN+i-start),b.get(startN+i-start+1));
                b.remove(startN+i-start);b.remove(startN+i-start);b.add(startN+i-start,temp);a.remove(i);}else{double temp =Sub.sub(b.get(startN+i-start),b.get(startN+i-start+1));

                b.remove(startN+i-start);b.remove(startN+i-start);b.add(startN+i-start,temp);a.remove(i);}}else{System.out.println("basic运算错误!");}}return b.get(startN);   //所有的符号计算完,number中的startN所指的数就是要返回的结果值
}

目前为止,我们已经可以计算不带括号的表达式了,下面我要说的就是比较麻烦一点的带括号运算,其思路就是传入容器的一部分到上述的无括号运算函数中,这里一部分是指一个小括号里的内容,也就是说下面要介绍的是一个容器吞吐的函数,它的作用就是依照括号的顺序来计算表达式,先将表达式里所有的括号从右向左从里向外地计算完,剩下没有括号的表达式再做最后一次运算可得最终结果,因此搞明白如何匹配括号是下面这个函数的重点。

代码实现:
int leftRCount=0,leftRLastindex=-1,leftNindex=0,rightRindex=0; //leftRCount为左括号数,leftRLastindex指向容器中最后一个左括号,leftRindex指向最后一个左括号,rightRindex指向最后一个右括号。for(int i=0;i<sign.size();i++){       //计数左括号数if(sign.get(i).equals('(')){leftRCount++;}
}
if(leftRCount==0){       //如果没有左括号则表达式中无括号计算display.setText(String.format("%.5f",BasicCompute.compute_withoutR(sign,0,sign.size(),number,0)));sign.clear();number.clear();
}else {                             
    for (int loop = 0; loop < leftRCount; loop++) {       //有几个左括号我们就要计算几次括号内容for (int i = 0; i < sign.size(); i++) {if (sign.get(i).equals('(')) {leftRLastindex = i;                    //确定leftRLastindex
}}
        for (int i = 0; i < sign.size(); i++) {if (i < leftRLastindex && (sign.get(i).equals('+') || sign.get(i).equals('-') || sign.get(i).equals('*') || sign.get(i).equals('/'))) {leftNindex++;                       //确定leftRindex
}if (i > leftRLastindex && sign.get(i).equals(')')) {rightRindex = i;                     //确定rightRindexbreak;}}double temp = BasicCompute.compute_withoutR(sign, leftRLastindex + 1, rightRindex - leftRLastindex - 1, number, leftNindex);
        sign.remove(leftRLastindex);           //每计算一次都要把该次的小括号从sign中移除
        sign.remove(leftRLastindex);
        leftNindex = 0;}temp=String.format("%.5f", BasicCompute.compute_withoutR(sign, 0, sign.size(), number, 0));            //本次运算是括号都计算后的最后一次无括号运算,是括号运算的最后一步,相当于上面的无括号运算。display.setText(String.format("%.5f", BasicCompute.compute_withoutR(sign, 0, sign.size(), number, 0)));sign.clear();number.clear();}
return temp; //temp为最终的计算值

到现在为止计算器的基本内容也是核心内容就讲解完毕了,剩下的其它科学运算建议采用隔离法,意思是在输入表达式的时候就让特殊的计算进行完毕,让后其结果值返回至计算器显示文本中,作为表达式的一部分,而不必所有的运算都要在输入表达式之后统一处理,另外还有精度、表达式输入正确检测、错误提示等细节功能需要依据个人风格来完成。

最后我们来总结一下这个算法的优点与缺点:

优点:函数分工清除方便调用,算法无需递归和堆栈以及树,理解方便,计算简便,所用资源少,所有的处理都在两个容器中完成,体现了游标的实用。
缺点:博主至今没找到。

												

安卓(java)计算器简单实现相关推荐

  1. java计算器简单源代码_java 简单的计算器程序实例代码

    java 简单的计算器程序 实现实例: import java.awt.*; import java.awt.event.*; import javax.swing.*; public class C ...

  2. java计算器简单吗,java简单计算器

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 无聊做个java加减乘除计算器,int型,没有小数,,呵呵,,真特么无聊,, package swing; import javax.swing.*; i ...

  3. 逗号运算符java_简单的java计算器 实现了重复标点及运算符连点限制

    今天练习了一个简约的java计算器的实现,特此阿萌分享代码给大家,本计算器代码也许有冗余,但是达到的限制效果还是比较完好的. 程序的实现还是比较简单的,而且代码也比较乱,想到那写到哪,但是对于作为练习 ...

  4. 用Java实现简单的计算器

    用Java实现简单的计算器 ​ 本计算器实现了最简单的四则运算,界面简洁,小伙伴可以根据自己的需要再此基础上进行修改,可拓展性强 效果图: 代码: public class Counter exten ...

  5. JAVA制作简单的计算器

    今天我们来学习做一个桌面的简单计算器.之所以说简单,是因为能完成的运算简单,只有加减乘除四则运算,远远不能跟那些功能完备的科学计算器相比.而且其中实现的思路也很简单. 关键词:java计算器,简单计算 ...

  6. 一个最简单的java计算器

    学习java的第三天,想检验一下前两天的学习成果,于是仿照着以前做的C语言计算器做了一个最为简单的java计算器(望大哥们指导) 总结:遇到的问题 0.上传博客要封面emmmm,不知道传什么,那就附一 ...

  7. Calcu 计算器简单去广告教程+修改应用名称

    Calcu Calcu是安卓手机上的一款简约,小巧,强大的计算器. 简洁.美观.强大,这是开发者对 CALCU 的定义.12 种主题可选,按键可自定义,可以说 CALCU 是一部可私人定制的计算器. ...

  8. java计算器注释_java计算器实现,百行代码,清晰注释

    写安卓写了三年有余了吧!今天无聊,在网上看看安卓的计算器居然没有一个实现的好的,真实让人心寒啊! 闲着无聊,我也写了一个java实现计算器,代码简单易懂,稍微有那么点不好懂的我都写了详细的注释的! 那 ...

  9. 安卓与HTML简单的交互使用

    安卓与HTML简单的交互使用 实现通过java代码与HTML的一个互相操作. 准备工作: 1.新建Android工程,在布局文件中添加WebView控件. 2.准备一个HTML文件,放在src/mai ...

  10. 计算机JAVA设计软件,基于Java计算器小软件的设计与实现.doc

    某某大学 毕业论文 题 目: 基于Java计算器小软件设计 学生姓名: ****** 学生学号: ********** 系 别: **************** 专 业: ************ ...

最新文章

  1. Python的pycurl库升级升级失败的解决方法
  2. Java语言的替代品:JVM的新编程语言开源
  3. html登录注册的正则,怎么用html5编写用户注册验证程序
  4. 操作系统:再见CentOS,将于本月底终止维护!
  5. linux系统搭建ftp服务器--只给某个用户访问其默认目录下的文件
  6. 解决Coldfusion连接MySQL数据库的问题
  7. 椭圆极点极线性质_笔记:关于极点极线的一些思考
  8. 国际版多时区设计方案【转】
  9. linux怎么查看vip地址,rac环境vip在linux下的连接信息
  10. ap计算机知识点总结,AP统计学考试知识点汇总
  11. Python wxpython篇 | Python生态库之图形用户界面开发库 “wxPython “ 的安装及使用(附. 使用pyinstaller 库打包Python随机点名小程序程序.exe文件)
  12. Android 打造炫目的圆形菜单 秒秒钟高仿建行圆形菜单
  13. mysql中week()函数
  14. Android 框架问题分析案例 - 谁杀了桌面?
  15. 51cto学院微信支付实战对接开发视频教程
  16. postgresql11.2修改分区表中复合索引字段长度遇到的BUG
  17. 点心云折腾记之网络篇
  18. java通过poi-tl模板引擎生成表格(Word)
  19. python3实现微信自动聊天
  20. 专利申请的详细流程和时间

热门文章

  1. Microsoft SQL Server 2000 Service Pack 3a
  2. Discuz!无法连接阿里云RDS数据库代理问题的处理方案
  3. unity 模拟引力
  4. 引力波,你果真懂了吗?
  5. Glide系列(四) — Glide缓存流程分析
  6. UED上半年工作总结
  7. 卡方分布、F分布、t分布和正态分布的关系
  8. centos8下重启网卡命令_Centos 8重启网卡命令
  9. shiro反序列化漏洞学习(工具+原理+复现)
  10. Java经典面试题—— int 和 Integer 有什么区别?谈谈 Integer 的值缓存范围