栈的应用1(计算器)

总述

本篇文章主要介绍这种数据结构在计算器的实现中的应用,核心思想即为如何实现中缀表达式转换为后缀表达式

思路分析

  1. 基本概念
    1. 我们都知道1个表达式是由运算符、数字以及括号组成。例如:1-(2+3)*5,在计算的时候,我们首先计算括号中的内容,然后根据运算符的优先级的高低去进行相应的计算。我们平常见到的这种表达式即为中缀表达式
    2. 什么是后缀表达式?后缀表达式又被称为逆波兰表达式,是一种没有括号,严格遵循从左到右进行运算的表达式。对于1-(2+3)*5这个中缀表达式,对应的后缀表达式即为1 2 3 + 5 * -,后缀表达式的特点即为从左至右遇到运算符就将离该运算符最近的两个数进行运算,即
      1. 从左至右 1 2 3,然后遇到+,则对2,3进行加法运算得到5
      2. 然后继续向右遇见5 和 * ,然后对 5 5进行乘法运算得到25
      3. 最后遇到 - ,对1 25进行减法运算得到-24
    3. 中缀表达式明显是符合我们思考的方式,但对于计算机而言,它无法很高效的进行"摘取"运算,它只能规矩的从左到右进行运算,因此想要实现计算器的功能,中缀表达式转为后缀表达式的实现是十分必要的
    4. 栈:栈是一种先入后出的有序列表,是限制线性表中元素的插入与删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端为变化的一端,称为栈顶(top****),另一端为固定的一端,称为栈底(bottom)
  2. 思路分析
    1. 为什么要用栈去实现表达式的计算呢?前面我们已经说过后缀表达式的作用,因此我们在对后缀表达式进行遍历时肯定是从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算,并将结果入栈,重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。图解:在这里插入图片描述

    2. 中缀表达式转为后缀表达式思路

      1. 初始化两个栈,运算符栈s1和数字栈s2
      2. 从左至右扫面中缀表达式
      3. 遇到操作数时,将其压s2
      4. 遇到运算符时,比较其与s1栈顶运算符的优先级
        1. 如果s1为空,或栈顶元素为’(‘,则直接将运算符入栈s1
        2. 如果优先级比栈顶运算符高,直接将运算符入栈s1
        3. 否则将s1中的栈顶元素弹出并加入到s2中,回到4.1与s1中新的栈顶元素比较
      5. 遇到括号时
        1. 左括号:直接压入s1
        2. 右括号,依次弹出s1栈顶的运算符并加入s2,直到遇到左括号为止,此时将这一对小括号丢弃
      6. 重复2~5,直到表达式的最右边
      7. 将s1中剩余的运算符依次弹出并压入s2
      8. 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
    3. 图解:(以1-(2+3)*5这个表达式进行图解)
      在这里插入图片描述

相关代码片段

/**
 * 中缀表达式转后缀表达式
 * @author qiu
 * @version 1.8.0
 */
public class Suffix {
    public static void main(String[] args) {
        String s = "1+((2+3)*4)-5";
        System.out.println(transform(s));
        System.out.println(transform1(transform(s)));
    }

    /**
     * 中缀表达式转为后缀表达式
     */
     public static List<String> transform1(List<String> ls){
         Stack<String> s1 = new Stack<>();
         List<String> s2 = new ArrayList<>();
         for(String item:ls){
             //多位数直接加入到集合:正则表达式
             if(item.matches("\\d+")){
                 s2.add(item);
             }else if("(".equals(item)||s1.empty()){
                 //左括号直接入符号栈
                 s1.push(item);
             }else if(")".equals(item)){
                 //右括号则将栈中符号元素加入到集合中直到运算符栈顶元素为左括号
                 while(!"(".equals(s1.peek())){
                     s2.add(s1.pop());
                 }
                 //记得将左括号去掉
                 s1.pop();
             }else{
                 //运算符则与栈顶元素进行比较若为空或左括号则直接入栈
                 //若该运算符有优先级高于栈顶元素的优先级则直接入栈
                 //优先级低于则一直弹出栈顶元素直到不满足优先级低于的条件后再将运算符入栈
                 while(!s1.empty()&&operation(item)<=operation(s1.peek())){
                     s2.add(s1.pop());
                 }
                 s1.push(item);
             }
         }
         while(!s1.empty()){
             s2.add(s1.pop());
         }
         return s2;
    }

    public static int operation(String s){
         if("+".equals(s)||"-".equals(s)){
             return 1;
         }
         if("*".equals(s)||"/".equals(s)){
             return 2;
         }
        return 0;
    }
    /**
     * 将字符串形式的中缀表达式转换为集合存储
     * @param s
     * @return
     */
    public static List<String> transform(String s){
        List<String> ls = new ArrayList<>();
        int index = 0;
        char ch = ' ';
        String str = "";
        while(true){
            if((ch=s.charAt(index)) <48||(ch = s.charAt(index))>57){
                //非数字直接入集合
                ls.add(ch+"");
                index++;
            }else{
                //是数字要考虑多位数拼接问题
                while(index < s.length()&&(ch =s.charAt(index))>=48&&(ch = s.charAt(index))<=57){
                    str+=ch;
                    index++;
                }
                ls.add(str);
                str = "";
            }
            if(index == s.length()){
                break;
            }
        }
        return ls;
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
经过这学期对数据结构的学习, 我们学习了理论知识, 了解了数据结构设计的思想, 这些知识都为我们的下一步学习打下了坚实的基础。通过课程设计,一方面是为了检查 我们一个学期来我们学习的成果,另一方面也是为了让我们进一步的掌握和运用它,同 时也让我们认清自己的不加以弥补和加强。足之处和薄弱环节,加以弥补和加强。 说起数据结构,它为程序提供了一种思想。计算机本身是无生命的机器,要是计算 机能够运行起来,为人类完成各种各样的工作,就必须让他执行相应的程序,这些程序 都是依靠程序设计语言编写出来的。它是一种思想,在编写程序时可以方便、灵活地运 用。同时,他还向程序员提供了直接操作计算机硬件的功能,具备低级语言的特点,适 合各种类型的软件开发。 说到课程设计,要明确自己的目标。在课设前要明确实训的相关要点,课程设计为 学生提供了一个既动手又动脑,独立实践的机会,将课本上的理论知识和实际有机的结 合起来,锻炼分析解决实际问题的能力。提高适应实际,实践编程的能力。课程设计的 基本理论是该课程设计的 C 语言为基础,掌握程序设计方法,为科学研究中的基层开发 工作奠定良好基础;同时培养学生的分析能力、设计能力和整体设计思想,以提高学生 的科学研究素质和在工作岗位中的具体应用能力。课程设计内容和基本要求,首先课程 设计内容是利用学到的编程知识和编程技巧,通过布置具有一定难度的程序设计题目, 熟悉程序编写,及时查究错误,独立完成。 通过本次课程设计, 自学掌握了随机函数与文件读写的知识, 独立完成了设计任务, 虽然思路和想法还有些不成熟,但是对自己的设计能力有很大的提高,今后仍要更加努 力的深入钻研,是自己的能力有进一步的提高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

囚蕤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值