文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android实践(计算器的数据结构实现)

2022-06-06 13:14

关注

新的知识,新的开始。

接下来一起探讨使用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


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯