这是中国大学慕课移动终端应用开发的网课作业7,我会持续更新我的作业,如果有需要关注一下吧
说明1.本计算器利用逆波兰式能实现加减乘除复合运算
2.第一个数字输入小数点能自动补全为 0.
3.能检测重复输入小数点情况
4.能检测式子语法正确情况
如果发现bug,或者有优化方案,可评论或私信联系我
界面展示
主题逻辑 MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.example.course8.model.LinkQueue;
import com.example.course8.model.LinkStack;
public class MainActivity extends AppCompatActivity {
private EditText mEditTextShow; //用于显示的编辑框
private String strFormula = ""; //用于记录算式
private boolean isFirstChar = true; //记录判断是不是第一个字符
private String tempNumber = "";//用于记录一个数字,为了判断是否连续输入小数点
private boolean newCalc = true;//用于记录是否是新的一轮计算
private void init(){
mEditTextShow = findViewById(R.id.edit_show);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
//执行按到非功能键的时候执行的操作
public void addFormula(View v){
if (newCalc){//新一轮计算
cleanCalc();
newCalc = false;
}
String value = "";
switch(v.getId()){
case R.id.number0:
value = "0";
break;
case R.id.number1:
value = "1";
break;
case R.id.number2:
value = "2";
break;
case R.id.number3:
value = "3";
break;
case R.id.number4:
value = "4";
break;
case R.id.number5:
value = "5";
break;
case R.id.number6:
value = "6";
break;
case R.id.number7:
value = "7";
break;
case R.id.number8:
value = "8";
break;
case R.id.number9:
value = "9";
break;
case R.id.number_point:
value = ".";
break;
case R.id.sub:
value = "-";
break;
case R.id.add:
value = "+";
break;
case R.id.multiplication:
value = "*";
break;
case R.id.division:
value = "/";
break;
}
//如果是第一个符号
if (isFirstChar){
if (isNumber(value)){//如果是数字
if (value.equals(".")){ //如果是小数点
strFormula = "0.";
}else {
strFormula = value; //添加进式子
}
tempNumber = strFormula;
isFirstChar = false;
}else{ //是运算符
if (value.equals("+")||value.equals("-")){ //加减默认是正负号
strFormula = "0"+value;
isFirstChar = false;
}else {//是乘除,不符合
Toast.makeText(MainActivity.this,value+"不可放在式子最前端",Toast.LENGTH_SHORT).show();
}
}
mEditTextShow.setText(strFormula); //显示在界面上
}else {//不是第一个字符
//判断符不符合规则
if (isNumber(value)){//如果是数字
if (value.equals(".")){
if (tempNumber.indexOf(".")>-1){//已经有小数点了
Toast.makeText(MainActivity.this,"不可重复放置小数点",Toast.LENGTH_SHORT).show();
}else if (isOperator(getLastStr(strFormula))){
Toast.makeText(MainActivity.this,"运算符后不可放置小数点",Toast.LENGTH_SHORT).show();
}else {
strFormula += ".";
tempNumber += ".";
}
}else { //不是小数点
strFormula += value;
tempNumber += value;
}
}else {//是符号
if (isOperator(getLastStr(strFormula))){//如果式子最后一个字符是符号
Toast.makeText(MainActivity.this,"算术符号不符规则",Toast.LENGTH_SHORT).show();
}else {
strFormula += value; //增加式子
tempNumber="";//重置数字暂存
}
}
//更新ui
mEditTextShow.setText(strFormula);
}
}
//按到等于键
public void equal(View v) throws Exception {
if (newCalc){//新一轮计算
cleanCalc();
newCalc = false;
}
//判断输入的式子是否合法
if (isLegal(strFormula)){
//获取式子的中缀表达式的队列
LinkQueue infixQueue = getInfixQueue(strFormula);
//获取后缀表达式
LinkQueue suffixQueue = getSuffixQueue(infixQueue);
//计算
LinkStack tempStack = new LinkStack(); //中间栈
int length = suffixQueue.length();
for(int i = 0;suffixQueue != null && i < length;i++){
String c = (String) suffixQueue.poll();//从后缀表达式中取出第一个
if(isOperator(c)){//当为操作符的时候
//取出两个操作数
double d2 = Double.valueOf(tempStack.pop().toString());
double d1 = Double.valueOf(tempStack.pop().toString());
double d3 = 0;
if(c.equals("+")){
d3 = d1 + d2;
}else if(c.equals("-")){
d3 = d1 - d2;
}else if(c.equals("*")){
d3 = d1 * d2;
}else if(c.equals("/")){
if (d2==0){
Toast.makeText(MainActivity.this,"0不能作为被除数",Toast.LENGTH_SHORT).show();
return;
}
d3 = d1 / d2;
}
tempStack.push(d3);
}else{ //为操作数时候
tempStack.push(c);
}
}
mEditTextShow.setText(""+tempStack.pop());//返回运算结果
newCalc = true;//新一轮计算标志
}
}
//将中缀表达式转换为逆波兰式,即返回一个后缀队列
public LinkQueue getSuffixQueue(LinkQueue infixQueue) throws Exception {
LinkQueue suffixQueue = new LinkQueue();
LinkStack tempStack = new LinkStack(); //中间栈,运算时存储运算符
int length = infixQueue.length();//因为这队列是动态的,所以只能用固定的长度值
for(int i = 0;(infixQueue!=null)&&i= priority(c)){
suffixQueue.offer(ac);
ac = (String) tempStack.pop();
}
if(ac!=null){//若最后一次取出的优先级低的操作符,重新压栈
tempStack.push(ac);
}
}
tempStack.push(c);
}else{//为操作数,将其添加到后缀表达式的队列末尾,里面有-1
suffixQueue.offer(c);
}
}
}
while(!tempStack.isEmpty()){//栈中剩余的所有操作符挨个进入后缀表达式
suffixQueue.offer(tempStack.pop());
}
return suffixQueue;
}
//判断运算法的优先级
public int priority(String c){
if(c.equals("*")||c.equals("/")){
return 2;
}else if(c.equals("-")||c.equals("+")){
return 1;
}else{
return 0;
}
}
//将输入的字符串式子转换成队列,运算符单独为一个单元,数字为一个单元
private LinkQueue getInfixQueue(String value)throws Exception{
//翻转字符
value = new StringBuilder(value).reverse().toString();
LinkQueue queue = new LinkQueue();
String numberStr="";
while (value.length()>0){
if (isNumber(getLastStr(value))){
numberStr += getLastStr(value);
value = deleteLastStr(value);
}else {
queue.offer(numberStr);
numberStr="";
queue.offer(getLastStr(value));
value = deleteLastStr(value);
}
}
queue.offer(numberStr);
return queue;
}
//判断输入的式子是否合法的方法
private boolean isLegal(String value){
if (value.equals("")){ //啥也没有
Toast.makeText(MainActivity.this,"无计算内容",Toast.LENGTH_SHORT).show();
return false;
}else if (isOperator(getLastStr(value))){ //式子以运算符结尾
Toast.makeText(MainActivity.this,"算式不允以运算符结尾",Toast.LENGTH_SHORT).show();
return false;
}else if (getLastStr(value).equals(".")){
Toast.makeText(MainActivity.this,"算式不允以小数点结尾",Toast.LENGTH_SHORT).show();
return false;
}else {
return true;
}
}
//按到删除键
public void delete(View v){
if (newCalc){//新一轮计算
cleanCalc();
newCalc = false;
}
if (strFormula.length()>0){
strFormula = deleteLastStr(strFormula);
mEditTextShow.setText(strFormula);
if (strFormula.length()==0){//删除过后为0,则执行清除操作
cleanCalc();
newCalc = false;
}
}else {
isFirstChar = true;
Toast.makeText(MainActivity.this,"无内容可后退",Toast.LENGTH_SHORT).show();
}
}
//按到清除键
public void clean(View v){
cleanCalc();
}
//清除计算
private void cleanCalc(){
mEditTextShow.setText("");
strFormula = ""; //用于记录算式
isFirstChar = true; //记录判断是不是第一个字符
tempNumber = "";//用于记录一个数字,为了判断是否连续输入小数点
newCalc = true;//用于记录是否是新的一轮计算
}
//判断是不是数字
private boolean isNumber(String value){
return "0123456789.".indexOf(value)>-1;
}
//判断是不是算术符号
private boolean isOperator(String value){
return "+-*/".indexOf(value)>-1;
}
//获取一个字符串最后一个字符
private String getLastStr(String value){
return value.substring(value.length()-1);
}
//获取一个字符串除了最后一个字符的其他字符
private String deleteLastStr(String value){
return value.substring(0,value.length()-1);
}
}
风格文件 styles.xml
@color/colorPrimary
@color/colorPrimaryDark
@color/colorAccent
30dp
5dp
#fff
1
30dp
5dp
#F8E6AC
1
颜色文件 colors.xml
#008577
#00574B
#D81B60
#F3F3F3
#D9F8F8
#F7BCB7
作者:大青儿