新的知识,新的开始。
接下来一起探讨使用Android技术解决计算器诸多问题,首先这个方法并不是适合所有人,有数据结构基础的同学可以稍微看看。
一般实现Android计算器都是只能进行例如 x + y = z的操作,但是需要实现类似于a + b * c = d的操作需要使用到逆波兰式。
下面解释一下逆波兰式的功能,人类认识中缀表达式,例如a+b*c,但是计算机只会按部就班的操作(a+b)*c,这样就与我们的目的背道而驰了,所以我们得将中缀表达式转化为后缀表达式,观察如下表格:
中缀表达式 | 后缀表达式 |
a+b*c | abc*+ |
a*b+c | ad*c+ |
我们所知 ÷× 的优先级比 + - 高。那我们如何使用后缀表达式呢?看如下图
栈底----->栈顶 |
a 没有两个数字 |
ab 有两个数字则需要评判下一位是不是运算符 |
abc 显然下一位并不是运算符,则再次评判下一位 |
abc* 这里可以运行b*c = z操作并压入栈中 |
az 继续评判 |
az+ 运算完成 (b*c)+a |
下来我们看一下该代码是如何实现的。
static Stack op = new Stack();
public static Float getv(char op, Float f1, Float f2) {
if (op == '+') return f2 + f1;
else if (op == '-') return f2 - f1;
else if (op == '*') return f2 * f1;
else if (op == '/') return f2 / f1;
else return Float.valueOf(-0);
}
public static float calrp(LinkedList rp) {
Stack v = new Stack();
int len = rp.size();
for (int i = 0; i < len; i++) {
InnerOperateChar ch =rp.get(i);
//如果是数字则压栈
if (ch.isNum()) v.push(Float.parseFloat(ch.getNumber()));
//非数字进行操作压栈
else v.push(getv(ch.getOperater(), v.pop(), v.pop()));
}
return v.pop();
}
那我们再往前推进,如何生成后缀表达式呢?
我们仔细观察一下中缀转化为后缀的过程。
a+b*c -----> abc*+ |
元素位置不变,则说明遇见数字则直接加入结果行列,那遇见运算符呢?
接下来一步一步进行模拟。
result | op(栈) | 操作讲解 |
a | a直接加入result | |
a | + | +入栈 |
ab | + | b直接加入result |
ab | +* | *入栈 |
ab* | + | *出栈 |
ab*c | + | c直接加入result |
ab*c+ | +出栈 |
过程捕捉:在遇见+-运算时候需要将之前的op栈的元素弹出并加入至result中 ,在遇见*/运算符时,与之前的操作一直,不过遇见同等运算等级的弹出元素需要停止。
以下是Java源程序。
public static LinkedList getrp(LinkedList s) {
int len = s.size();
LinkedList result = new LinkedList();
for (int i = 0; i < len; i++) {
InnerOperateChar ch = s.get(i);
if (ch.isNum()) {
result.add(ch);
} else if (!ch.isNum()) {
//如果是运算符的话
char oppo = ch.getOperater();
if (oppo == '+' || oppo == '-') {
while (!op.empty()) {
result.add(op.pop());
}
op.push(ch);
}
if (oppo == '*' || oppo == '/') {
while (!op.empty() && op.peek().getOperater() == '*') {
result.add(op.pop());
}
op.push(ch);
}
}
}
while (!op.empty()) {
InnerOperateChar temp = op.pop();
result.add(temp);
}
return result;
}
接下来解析工程中的重要数据结构(即运算符与数字集合类)
如下为创建的过程,再次声明,这里的数据结构是为了简化后期程序的难度。
//添加数字
linkedList.add(new InnerOperateChar("1"));
//添加运算符
linkedList.add(new InnerOperateChar('-'));
package com.example.thirdlesson;
public class InnerOperateChar {
private String number;
private char operater;
private boolean isNum;
public InnerOperateChar(String number) {
this.number = number;
this.operater = '#';
this.isNum = true;
}
public InnerOperateChar(char operater) {
this.number ="#";
this.operater = operater;
this.isNum = false;
}
public boolean isNum() {
return isNum;
}
public void setNum(boolean num) {
isNum = num;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public char getOperater() {
return operater;
}
public void setOperater(char operater) {
this.operater = operater;
}
}
那我们开始我们的布局排版吧。
这是我们的预期效果图
完整xml文件在最后面
接下来我们查看我们TextView中的两个元素
TextView showResult;//即xml中的showResult
TextView showAll;//即xml中的showAll
showAll = this.findViewById(R.id.showAll);
showResult = this.findViewById(R.id.showResult);
同时我们也设定了一个参数,用来将当前输入的数字或者运算符加入进去。
//单一数据
StringBuffer paramOne = new StringBuffer();
接下来是细节部分:
此操作为清零操作
实现现象:
实现代码:
btnC = this.findViewById(R.id.buttonC);
btnC.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//清零
//1.paramOne清零
//2.showAll清零
//3.showResult清零
//4.linkedList清空
paramOne = new StringBuffer();
showAll.setText("");
showResult.setText("");
linkedList.clear();
}
});
此操作为删除操作
主要重点:
当前所有的参数都为空,则为当前存放字符为空并且当前链表为空
当前paramOne有参数,如果进行当前paramOne删除,并同步
如果paramOne没参数,则提取linkedList的最后一个元素lastOne
lastOne如果是运算符,则直接删除即可
lastOne如果是字符串,比如123.1则需要提取至paramOne中进行删除同步
实现现象:
实现源码:
btnDel = this.findViewById(R.id.buttonDEL);
btnDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//删除最后一个
//1.如果paramOne还有数据就进行删除
//1.1 并且showResult需要同步删除
//2.如果paramOne没数据,提取linkedList最后一个
//2.1 如果是运算符,直接linkedList移除最后一个
//2.2 如果是字符串,则将paramOne赋值为linkedList最后一个元素,并同步showResult
//2.3 同步showAll
//避免删除闪退
if(linkedList.size()==0 && paramOne.length()==0){
return;
}
if(paramOne.length()!=0){
paramOne=new StringBuffer(paramOne.subSequence(0,paramOne.length()-1));
showResult.setText(paramOne.toString());
}
else{
//如果是运算符的话,不需要任何操作
InnerOperateChar lastElem = linkedList.removeLast();
if(lastElem.isNum()){
String lastNum = lastElem.getNumber();
paramOne = new StringBuffer(lastNum.substring(0,lastNum.length()-1));
showResult.setText(paramOne.toString());
}else {
;
}
showAll.setText(AllToString(linkedList));
}
}
});
此操作为点击数字操作
实现代码:
switch (v.getId()) {
case R.id.button0:
//上端不用改变,只有进行运算的时候入队即可
paramOne.append("0");
showResult.setText(paramOne.toString());
break;
}
此操作为小数点处理
试验现象:
主要难点:需要判断当前ParamOne的长度是否是0,如果是的话则就是这个操作,如果包含.如果包含则不需要再添加,否则添加。
实现代码:
case R.id.buttonDOT:
//如果出现再没数字的情况下直接按下.则直接变为0. 然后再进行后续操作
if(paramOne.length()==0){
paramOne.append("0.");
}else{
//如果出现1.1 然后还想点. 则不生效否则添加
if(paramOne.toString().contains(".")){
;
}else{
paramOne.append(".");
}
}
showResult.setText(paramOne.toString());
break;
此操作为点击运算符操作:
实现大致方法:
需要paramOne入队
paramOne清空
操作符入队
showAll显示
showResult清空
实现代码:
case R.id.buttonPLUS:
//进行加运算
//1.需要paramOne入队
//2.paramOne清空
//3.操作符入队
//4.showAll显示
//5.showResult清空
//以免造成 12. - 12得现象
if(paramOne.charAt(paramOne.length()-1)=='.'){
paramOne = new StringBuffer(paramOne.subSequence(0,paramOne.length()-1));
}
linkedList.add(new InnerOperateChar(paramOne.toString()));
paramOne = new StringBuffer();
linkedList.add(new InnerOperateChar('+'));
showAll.setText(AllToString(linkedList));
showResult.setText("");
break;
此操作为负数与减法操作:
实现现象:
实现代码:
case R.id.buttonSUB:
//进行-运算
//如果paramOne 长度不为0的话,那就是要进行 - 减操作
if(paramOne.length()!=0){
if(paramOne.charAt(paramOne.length()-1)=='.'){
paramOne = new StringBuffer(paramOne.subSequence(0,paramOne.length()-1));
}
linkedList.add(new InnerOperateChar(paramOne.toString()));
paramOne = new StringBuffer();
linkedList.add(new InnerOperateChar('-'));
showAll.setText(AllToString(linkedList));
showResult.setText("");
}else {
paramOne.append("-");
showResult.setText(paramOne.toString());
}
进行结果运算:
主要实现源码:
btnIs = this.findViewById(R.id.buttonIS);
btnIs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
linkedList.add(new InnerOperateChar(paramOne.toString()));
paramOne = new StringBuffer();
showAll.setText(AllToString(linkedList));
OperateSu1 operateChar = new OperateSu1();
LinkedList suffer = operateChar.getrp(linkedList);
float result = operateChar.calrp(suffer);
showResult.setText(result+"");
}
});
最后就是完整代码了:
package com.example.thirdlesson;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Path;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.LinkedList;
public class MainActivity extends AppCompatActivity {
//清零,删除上一字符,等于
Button btnC, btnDel, btnIs;
//单一数据
StringBuffer paramOne = new StringBuffer();
Button[] buttons_num = new Button[11];
int[] btnId_num = {R.id.button0, R.id.button1, R.id.button2, R.id.button3, R.id.button4, R.id.button5, R.id.button6, R.id.button7, R.id.button8, R.id.button9, R.id.buttonDOT};
//放 + - * /的按钮
Button[] buttons_operate = new Button[4];
//+ - * /
int[] btnId_operate = {R.id.buttonPLUS, R.id.buttonSUB, R.id.buttonMUL, R.id.buttonDEV};
TextView showResult;
TextView showAll;
LinkedList linkedList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置内容视图
setContentView(R.layout.main_layout);
linkedList = new LinkedList();
//实例化对象
initView();
//绑定监听事件
//也可以在xml中这样写
//android:onClick="myClick"
myClick myClickClass = new myClick();
for (int i = 0; i < buttons_num.length; i++) {
buttons_num[i].setOnClickListener(myClickClass);
}
for (int i = 0; i < buttons_operate.length; i++) {
buttons_operate[i].setOnClickListener(myClickClass);
}
btnIs = this.findViewById(R.id.buttonIS);
btnIs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
linkedList.add(new InnerOperateChar(paramOne.toString()));
paramOne = new StringBuffer();
showAll.setText(AllToString(linkedList));
OperateSu1 operateChar = new OperateSu1();
LinkedList suffer = operateChar.getrp(linkedList);
float result = operateChar.calrp(suffer);
showResult.setText(result+"");
}
});
btnDel = this.findViewById(R.id.buttonDEL);
btnDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//删除最后一个
//1.如果paramOne还有数据就进行删除
//1.1 并且showResult需要同步删除
//2.如果paramOne没数据,提取linkedList最后一个
//2.1 如果是运算符,直接linkedList移除最后一个
//2.2 如果是字符串,则将paramOne赋值为linkedList最后一个元素,并同步showResult
//2.3 同步showAll
//避免闪退
if(linkedList.size()==0 && paramOne.length()==0){
return;
}
if(paramOne.length()!=0){
paramOne=new StringBuffer(paramOne.subSequence(0,paramOne.length()-1));
showResult.setText(paramOne.toString());
}
else{
//如果是运算符的话,不需要任何操作
InnerOperateChar lastElem = linkedList.removeLast();
if(lastElem.isNum()){
String lastNum = lastElem.getNumber();
paramOne = new StringBuffer(lastNum.substring(0,lastNum.length()-1));
showResult.setText(paramOne.toString());
}else {
;
}
showAll.setText(AllToString(linkedList));
}
}
});
btnC = this.findViewById(R.id.buttonC);
btnC.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//清零
//1.paramOne清零
//2.showAll清零
//3.showResult清零
//4.linkedList清空
paramOne = new StringBuffer();
showAll.setText("");
showResult.setText("");
linkedList.clear();
}
});
}
void initView() {
for (int i = 0; i < btnId_num.length; i++) {
buttons_num[i] = this.findViewById(btnId_num[i]);
}
for (int i = 0; i < btnId_operate.length; i++) {
buttons_operate[i] = this.findViewById(btnId_operate[i]);
}
showAll = this.findViewById(R.id.showAll);
showResult = this.findViewById(R.id.showResult);
}
class myClick implements View.OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button0:
//上端不用改变,只有进行运算的时候入队即可
paramOne.append("0");
showResult.setText(paramOne.toString());
break;
case R.id.button1:
paramOne.append("1");
showResult.setText(paramOne.toString());
break;
case R.id.button2:
paramOne.append("2");
showResult.setText(paramOne.toString());
break;
case R.id.button3:
paramOne.append("3");
showResult.setText(paramOne.toString());
break;
case R.id.button4:
paramOne.append("4");
showResult.setText(paramOne.toString());
break;
case R.id.button5:
paramOne.append("5");
showResult.setText(paramOne.toString());
break;
case R.id.button6:
paramOne.append("6");
showResult.setText(paramOne.toString());
break;
case R.id.button7:
paramOne.append("7");
showResult.setText(paramOne.toString());
break;
case R.id.button8:
paramOne.append("8");
showResult.setText(paramOne.toString());
break;
case R.id.button9:
paramOne.append("9");
showResult.setText(paramOne.toString());
break;
case R.id.buttonDOT:
//如果出现再没数字的情况下直接按下.则直接变为0. 然后再进行后续操作
if(paramOne.length()==0){
paramOne.append("0.");
}else{
//如果出现1.1 然后还想点. 则不生效否则添加
if(paramOne.toString().contains(".")){
;
}else{
paramOne.append(".");
}
}
showResult.setText(paramOne.toString());
break;
case R.id.buttonPLUS:
//进行加运算
//1.需要paramOne入队
//2.paramOne清空
//3.操作符入队
//4.showAll显示
//5.showResult清空
//以免造成 12. - 12得现象
if(paramOne.charAt(paramOne.length()-1)=='.'){
paramOne = new StringBuffer(paramOne.subSequence(0,paramOne.length()-1));
}
linkedList.add(new InnerOperateChar(paramOne.toString()));
paramOne = new StringBuffer();
linkedList.add(new InnerOperateChar('+'));
showAll.setText(AllToString(linkedList));
showResult.setText("");
break;
case R.id.buttonSUB:
//进行-运算
//如果paramOne 长度不为0的话,那就是要进行 - 减操作
if(paramOne.length()!=0){
if(paramOne.charAt(paramOne.length()-1)=='.'){
paramOne = new StringBuffer(paramOne.subSequence(0,paramOne.length()-1));
}
linkedList.add(new InnerOperateChar(paramOne.toString()));
paramOne = new StringBuffer();
linkedList.add(new InnerOperateChar('-'));
showAll.setText(AllToString(linkedList));
showResult.setText("");
}else {
paramOne.append("-");
showResult.setText(paramOne.toString());
}
break;
case R.id.buttonMUL:
//进行*运算
if(paramOne.charAt(paramOne.length()-1)=='.'){
paramOne = new StringBuffer(paramOne.subSequence(0,paramOne.length()-1));
}
linkedList.add(new InnerOperateChar(paramOne.toString()));
paramOne = new StringBuffer();
linkedList.add(new InnerOperateChar('*'));
showAll.setText(AllToString(linkedList));
showResult.setText("");
break;
case R.id.buttonDEV:
//进行/运算
if(paramOne.charAt(paramOne.length()-1)=='.'){
paramOne = new StringBuffer(paramOne.subSequence(0,paramOne.length()-1));
}
linkedList.add(new InnerOperateChar(paramOne.toString()));
paramOne = new StringBuffer();
linkedList.add(new InnerOperateChar('/'));
showAll.setText(AllToString(linkedList));
showResult.setText("");
break;
}
}
}
public String AllToString(LinkedList s) {
String result = "";
for(InnerOperateChar innerOperateChar:s){
if(innerOperateChar.isNum()){
result += innerOperateChar.getNumber();
}else{
result += " " +innerOperateChar.getOperater()+" ";
}
}
return result;
}
}
xml文件
package com.example.thirdlesson;
import java.util.LinkedList;
import java.util.Stack;
public class OperateSu1 {
static Stack op = new Stack();
public static Float getv(char op, Float f1, Float f2) {
if (op == '+') return f2 + f1;
else if (op == '-') return f2 - f1;
else if (op == '*') return f2 * f1;
else if (op == '/') return f2 / f1;
else return Float.valueOf(-0);
}
public static float calrp(LinkedList rp) {
Stack v = new Stack();
int len = rp.size();
for (int i = 0; i < len; i++) {
InnerOperateChar ch =rp.get(i);
//如果是数字则压栈
if (ch.isNum()) v.push(Float.parseFloat(ch.getNumber()));
//非数字进行操作压栈
else v.push(getv(ch.getOperater(), v.pop(), v.pop()));
}
return v.pop();
}
public static LinkedList getrp(LinkedList s) {
int len = s.size();
LinkedList result = new LinkedList();
for (int i = 0; i < len; i++) {
InnerOperateChar ch = s.get(i);
if (ch.isNum()) {
result.add(ch);
} else if (!ch.isNum()) {
//如果是运算符的话
char oppo = ch.getOperater();
if (oppo == '+' || oppo == '-') {
while (!op.empty()) {
result.add(op.pop());
}
op.push(ch);
}
if (oppo == '*' || oppo == '/') {
while (!op.empty() && op.peek().getOperater() == '*') {
result.add(op.pop());
}
op.push(ch);
}
}
}
while (!op.empty()) {
InnerOperateChar temp = op.pop();
result.add(temp);
}
return result;
}
// public static void main(String[] args) {
// LinkedList linkedList = new LinkedList();
// linkedList.add(new InnerOperateChar("1"));
// linkedList.add(new InnerOperateChar('+'));
// linkedList.add(new InnerOperateChar("11"));
// linkedList.add(new InnerOperateChar('*'));
// linkedList.add(new InnerOperateChar("3"));
// linkedList.add(new InnerOperateChar('-'));
// linkedList.add(new InnerOperateChar("8"));
// LinkedList paramString = getrp(linkedList);
// //1+22*33-8
//// System.out.println(paramString);
//
// System.out.println(calrp(paramString));
// }
}
作者:Bit_We