对于四则运算大家都不陌生了吧!
相信能看懂这篇文章上字的人基本都会算四则运算。但是怎么让计算机去解析这个四则运算呢?
计算机只能计算+ - * / % 如果四则运算的表达式中出现括号,那又该怎么办呢?这里呢,就需要用到一定的数学知识了!我们书写的四则运算表达式一般是用中缀式(eg:5*(2+3*(6-3)/5)+7),这样的字符串给计算机运算带来很大的困难,那么我这里引入后缀表达式如下:
这样太抽象了,来举几个例子给大家看看中缀表达式是怎么转换成后缀式子的
那我们怎么把中缀表达式转换成后缀表达式呢?看如下示例~~
我们用代码来看看怎么转换
private void calculator(String operation) { char[] opr = operation.toCharArray(); // 将字符串转换成字符数组 // 先在符号栈中加入'#',方便判断pop的时候是否取完符号 optr.push('#'); // 逐个字符解析 for (int i = 0; i < opr.length; i++) { char temp = opr[i]; // 如果是数字压入后缀式栈中 if ((int) temp >= 48 && (int) temp <= 57) { pofix.push(temp); } // 如果读到'#',表示表达式已经历遍完了 else if (temp == '#') { // 把剩下的运算符压入后缀表达式栈中 while (true) { char left = (char) optr.pop(); // 如果在运算符栈中读到'#',那么表示所有运算符已经读完 if (left == '#') { break; } else { pofix.push(left); } } } // 如果是运算符(包括括号) else { // 如果是左括号,压入运算符栈中 if (temp == '(') { optr.push('('); } // 如果是右括号,运算符出栈直到匹配到左括号 else if (temp == ')') { System.out.println("匹配到右括号"); while (true) { char getTop = (char) optr.pop(); // 如果是左括号,则一次匹配结束 if (getTop == '(') break; // 如果不是左括号,出运算符栈,压入后缀表达式栈 System.out.println("getTop = " + getTop); pofix.push(getTop); } } // 如果不是括号,和栈顶元素比较优先级,再确定是否入栈 else { // 获取栈顶元素 char topTemp = (char) optr.pop(); // 如果取得运算符优先级比栈顶的高,直接压入运算符栈 if (priority(temp) >priority(topTemp)) { System.out.println("topTemp = " + topTemp + " temp = " + temp); optr.push(topTemp); optr.push(temp); } else { // 如果低的话,就把栈顶运算符压入后缀式栈中,把取得运算符压入运算符栈中 optr.push(temp); pofix.push(topTemp); } } } } /** * 操作符优先级方法 * * @param ch * @return 优先级 */ private int priority(char ch) { switch (ch) { case '#': return 0; case '(': return 1; case '+': return 3; case '-': return 3; case '*': return 5; case '/': return 5; case ')': return 7; default: JOptionPane.showMessageDialog(null, "输入表达式中存在不合法字符"); return -1;// 因为不可能不匹配,除非表达式中存在不合法字符 } }
这样我们就已经实现了把中缀表达式转换成后缀表达式了!
有了后缀表达式,我们怎么去是实现计算呢?例如这个后缀表达式(12345+-*+),由于以上代码把后缀表达式放在了一个栈结构中,而且自顶向下是(+*-+54321),这样显然不好操作。我们给自定义栈中加了一个方法,把栈倒置。
package cn.jinyejun.experiment_Stack; /** * 用数组实现栈结构 * * @author 金晔俊 日期:2014.4.4 * @param <E> */ public class MyStack<E> { private Object stack[]; private final static int UPDATE_SIZE = 5; // 栈空间更新大小 private int top = 0; // 初始化栈顶 private int size = 0; // 初始化栈大小 /** * 构造方法,初始化一个大小为0的栈 */ public MyStack() { this(0); } /** * 构造方法,初始化一个大小为size的栈 * * @param size */ public MyStack(int size) { stack = new Object[size]; this.size = size; } /** * 入栈 * @param e */ public void push(E e) { // 如果栈满,增加栈大小 if (isFull()) { Object newStack[] = new Object[stack.length + UPDATE_SIZE]; for(int i=0;i<stack.length;i++){ newStack[i]=stack[i]; } stack = newStack; size = size + UPDATE_SIZE; // 更新栈大小 } stack[top++] = e; } /** * 出栈 * @return stack[top--]; */ public Object pop(){ //如果栈空,抛出异常 if(isEmpty()){ throw new java.lang.IndexOutOfBoundsException("栈空!"); }else{ Object topElement = stack[--top]; stack[top] = null; //清空栈顶 size--; return topElement; } } public int getSize(){ return size; } /** * 判断是否栈满 * @return top >= size */ public boolean isFull() { return top >= size; } /** * 判断是否空栈 * @return top == 0 */ public boolean isEmpty() { return top == 0; } /** * 倒置栈 * */ public void changeOrder(){ System.out.println("top-->?"+top); Object[] newStack = new Object[stack.length]; for(int i = top-1;i>=0;i--){ newStack[top-1-i] = stack[i]; } stack = newStack; System.out.println("转换后的栈————————"); for(int i = 0;i<top;i++){ System.out.println("change"+stack[i]); } } }
这样后缀表达式在栈中自顶向下就是这么存放了(12345+-*+),有了这个东西,我们可以自顶向下的方式去遍历这个栈,如果是数字就把数字放到一个新的栈结构(这里我们把它叫做计算栈)中,如果是运算符,就在运算栈里依次取出两个数字b,a进行相应计算(比如运算符是-,那么就是a-b),然后把计算得到的结构再放入计算栈中,直到遍历完后缀表达式存放的那个栈为止,然后取出计算栈中的数字就是表达式计算结果!
代码如下:
// 先把后缀表达式栈倒序 pofix.changeOrder(); // 遍历新的后缀表达式栈 while (!pofix.isEmpty()) { char tempOpr = (char) pofix.pop(); // 如果是数字送入计算栈 if (tempOpr>= '0' &&tempOpr<= '9'){ calStack.push((int)(tempOpr-48)); }else{ //如果不是取计算栈中的栈顶元素进行符号计算 int b = (int) calStack.pop(); int a = (int) calStack.pop(); int c; switch(tempOpr){ case '+': c = a+b; System.out.println("计算结果+ "+c); calStack.push(c); break; case '-': c = a-b; System.out.println("计算结果- "+c); calStack.push(c); break; case '*': c = a*b; System.out.println("计算结果* "+c); calStack.push(c); break; case '/': c = a/b; System.out.println("计算结果/ "+c); calStack.push(c); break; } } } int result = (int) calStack.pop(); System.out.println(result); }
完整版代码(包含了图形界面哦,以及在代码编写过程中的调试syso哦)
自定义栈类:
package cn.jinyejun.experiment_Stack; /** * 用数组实现栈结构 * * @author 金晔俊 日期:2014.4.4 * @param <E> */ public class MyStack<E> { private Object stack[]; private final static int UPDATE_SIZE = 5; // 栈空间更新大小 private int top = 0; // 初始化栈顶 private int size = 0; // 初始化栈大小 /** * 构造方法,初始化一个大小为0的栈 */ public MyStack() { this(0); } /** * 构造方法,初始化一个大小为size的栈 * * @param size */ public MyStack(int size) { stack = new Object[size]; this.size = size; } /** * 入栈 * @param e */ public void push(E e) { // 如果栈满,增加栈大小 if (isFull()) { Object newStack[] = new Object[stack.length + UPDATE_SIZE]; for(int i=0;i<stack.length;i++){ newStack[i]=stack[i]; } stack = newStack; size = size + UPDATE_SIZE; // 更新栈大小 } stack[top++] = e; } /** * 出栈 * @return stack[top--]; */ public Object pop(){ //如果栈空,抛出异常 if(isEmpty()){ throw new java.lang.IndexOutOfBoundsException("栈空!"); }else{ Object topElement = stack[--top]; stack[top] = null; //清空栈顶 size--; return topElement; } } public int getSize(){ return size; } /** * 判断是否栈满 * @return top >= size */ public boolean isFull() { return top >= size; } /** * 判断是否空栈 * @return top == 0 */ public boolean isEmpty() { return top == 0; } public void changeOrder(){ System.out.println("top-->?"+top); Object[] newStack = new Object[stack.length]; for(int i = top-1;i>=0;i--){ newStack[top-1-i] = stack[i]; } stack = newStack; System.out.println("转换后的栈————————"); for(int i = 0;i<top;i++){ System.out.println("change"+stack[i]); } } }
四则运算类:
package cn.jinyejun.experiment_Stack; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTextField; public class AnalyzeOperate extends JFrame { private MyStack<Character> optr = new MyStack<Character>(); // 操作符栈 private MyStack<Character> pofix = new MyStack<Character>(); // 后缀表达式栈 private MyStack<Integer> calStack = new MyStack<Integer>(); // 用于取后缀表达式栈中的元素计算栈 private JLabel jlb; private JLabel jlbr; private JLabel jlbp; private JTextField jtf; private JButton jbu; private String operation; // 存放表达式 public AnalyzeOperate() { initUI(); } // 初始化界面 private void initUI() { this.setTitle("用栈结构实现四则运算"); this.setLayout(new FlowLayout()); this.setSize(300, 150); this.setResizable(false); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 提示标签 jlb = new JLabel("请输入四则运算表达式"); jlbr = new JLabel("计算结果:"); jlbp = new JLabel("____"); // 实例化四则运算输入框和计算按钮 jtf = new JTextField(25); jbu = new JButton("calculator"); this.add(jlb); this.add(jtf); this.add(jbu); this.add(jlbr); this.add(jlbp); this.setVisible(true); jbu.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { operation = jtf.getText(); // 获取表达式字符串 calculator(operation + "#");// 解析表达式 } }); } /** * 解析表达式进行运算 * * @param operation */ private void calculator(String operation) { char[] opr = operation.toCharArray(); // 将字符串转换成字符数组 // 先在符号栈中加入'#',方便判断pop的时候是否取完符号 optr.push('#'); // 逐个字符解析 for (int i = 0; i < opr.length; i++) { char temp = opr[i]; // 如果是数字压入后缀式栈中 if ((int) temp >= 48 && (int) temp <= 57) { pofix.push(temp); } // 如果读到'#',表示表达式已经历遍完了 else if (temp == '#') { // 把剩下的运算符压入后缀表达式栈中 while (true) { char left = (char) optr.pop(); // 如果在运算符栈中读到'#',那么表示所有运算符已经读完 if (left == '#') { break; } else { pofix.push(left); } } } // 如果是运算符(包括括号) else { // 如果是左括号,压入运算符栈中 if (temp == '(') { optr.push('('); } // 如果是右括号,运算符出栈直到匹配到左括号 else if (temp == ')') { System.out.println("匹配到右括号"); while (true) { char getTop = (char) optr.pop(); // 如果是左括号,则一次匹配结束 if (getTop == '(') break; // 如果不是左括号,出运算符栈,压入后缀表达式栈 System.out.println("getTop = " + getTop); pofix.push(getTop); } } // 如果不是括号,和栈顶元素比较优先级,再确定是否入栈 else { // 获取栈顶元素 char topTemp = (char) optr.pop(); // 如果取得运算符优先级比栈顶的高,直接压入运算符栈 if (priority(temp) >priority(topTemp)) { System.out.println("topTemp = " + topTemp + " temp = " + temp); optr.push(topTemp); optr.push(temp); } else { // 如果低的话,就把栈顶运算符压入后缀式栈中,把取得运算符压入运算符栈中 optr.push(temp); pofix.push(topTemp); } } } } //转换前 // System.out.println("转换前的栈-------"); // while (!pofix.isEmpty()) { // System.out.println(pofix.pop()); // } // 先把后缀表达式栈倒序 pofix.changeOrder(); // while (!pofix.isEmpty()) { // System.out.println(pofix.pop()); // } // 遍历新的后缀表达式栈 while (!pofix.isEmpty()) { char tempOpr = (char) pofix.pop(); // 如果是数字送入计算栈 if (tempOpr>= '0' &&tempOpr<= '9'){ calStack.push((int)(tempOpr-48)); }else{ //如果不是取计算栈中的栈顶元素进行符号计算 int b = (int) calStack.pop(); int a = (int) calStack.pop(); int c; switch(tempOpr){ case '+': c = a+b; System.out.println("计算结果+ "+c); calStack.push(c); break; case '-': c = a-b; System.out.println("计算结果- "+c); calStack.push(c); break; case '*': c = a*b; System.out.println("计算结果* "+c); calStack.push(c); break; case '/': c = a/b; System.out.println("计算结果/ "+c); calStack.push(c); break; } } } int result = (int) calStack.pop(); System.out.println(result); jlbp.setText(""+result); this.repaint(); } /** * 操作符优先级方法 * * @param ch * @return 优先级 */ private int priority(char ch) { switch (ch) { case '#': return 0; case '(': return 1; case '+': return 3; case '-': return 3; case '*': return 5; case '/': return 5; case ')': return 7; default: JOptionPane.showMessageDialog(null, "输入表达式中存在不合法字符"); return -1;// 因为不可能不匹配,除非表达式中存在不合法字符 } } public static void main(String[] args) { new AnalyzeOperate(); } }
相关推荐
在本项目“C语言数据结构用栈实现四则运算”中,开发者利用栈这种数据结构来处理数学中的四则运算,包括加法(+)、减法(-)、乘法(*)和除法(/)。这种方法相比传统的递归或循环方式,通常更加简洁且易于理解。...
### 栈的四则运算实现及详解 #### 一、引言 在计算机科学中,栈是一种非常重要的数据结构,其遵循后进先出(LIFO, Last In First Out)的原则。栈通常用于解决需要“回溯”的问题,例如函数调用栈、括号匹配等问题...
本主题将详细探讨如何使用C语言实现数据结构中的栈来处理四则运算。 栈是一种线性数据结构,遵循“后进先出”(LIFO)原则。它类似于一个堆叠的盘子,最后放上去的盘子最先被取走。栈在计算中有很多应用,包括...
四则运算,即加法、减法、乘法和除法,是基本的算术运算,它们可以被有效地用栈来处理。 当我们谈论使用栈进行四则运算时,通常涉及以下几个关键步骤: 1. **表达式解析**:首先,我们需要将输入的数学表达式(如 ...
在C语言中,实现四则运算通常涉及到使用数据结构来模拟计算过程,这里采用的是栈(Stack)这一数据结构。栈是一种后进先出(LIFO, Last In First Out)的数据结构,非常适合处理运算符的优先级问题。在这个项目中,...
例如,`四则运算 (2).c`可能就是一个C语言版本的实现,其中包含解析表达式、处理运算符优先级和栈操作的函数。 总的来说,通过巧妙地运用栈的数据结构,我们可以有效地解决四则运算的问题,尤其是对于复杂表达式的...
在C#编程中,利用栈数据结构来解决四则运算,特别是处理包含多重括号和多位数的运算问题,是一种常见的方法。栈是一种后进先出(LIFO,Last In First Out)的数据结构,非常适合处理这类计算问题。下面将详细阐述...
总的来说,这个C语言项目展示了如何利用栈数据结构处理复杂的四则运算,尤其是涉及括号和大数的情况。它涵盖了基础的语法、运算符优先级、输入输出操作以及自定义数据结构的使用,这些都是C语言编程中不可或缺的知识...
本项目是利用C语言实现整数和小数的四则运算,特别是借助栈数据结构来处理运算符的优先级和括号表达式。以下是对这个项目的详细说明: 首先,栈是一种特殊的线性数据结构,遵循“后进先出”(LIFO)原则。在计算...
在这个四则运算练习软件的数据结构课设中,我们主要关注如何利用数据结构来设计一个高效、用户友好的运算练习系统。该软件可能包括加法、减法、乘法和除法等基本算术操作,为用户提供一个实践和提升数学技能的平台。...
总的来说,利用C++ STL的栈和队列实现四则运算是一种高效且易于理解的方法,它充分利用了数据结构特性来解决实际问题。通过这个过程,不仅可以学习到栈和队列的运用,还能加深对四则运算规则的理解。在压缩包中的`...
四则运算解析器是一种计算机程序,它能够接收包含加、减、乘、除等四则运算符的字符串表达式,并将其转化为可执行的计算过程。这个解析器通常用于解决基础的数学问题,对于编程初学者来说,理解并实现这样一个解析器...
链栈是一种特殊的栈数据结构,它...总的来说,这个“基于链栈的四则运算”项目提供了一个学习链栈数据结构和四则运算解析的好机会。通过实践和理解代码,开发者可以深化对链表、栈和运算符优先级的理解,提升编程技能。
本主题“双栈-四则运算”是数据结构在实际问题中的应用,具体而言,是利用两个栈来实现四则运算(加法、减法、乘法和除法)的计算。这种设计思路常见于解析表达式树、编译器设计以及简单的计算器程序中。 首先,让...
在本课程设计中,主要任务是使用C语言和数据结构实现基本的四则运算。这里采用了堆栈(Stack)的数据结构来处理运算过程中的运算符和操作数。堆栈是一种后进先出(LIFO)的数据结构,非常适合处理数学表达式中的...
总的来说,利用链式栈处理任意四则运算是一种常见的算法应用,它结合了数据结构和运算符优先级的概念,是计算机科学基础课程中的典型问题。通过这种方式,我们能够有效地解决复杂的数学表达式的计算,并为其他更复杂...
在计算机科学中,四则运算(加法、减法、乘法、除法)是基本的数学操作,而栈(Stack)作为一种数据结构,经常被用于处理这类问题,特别是涉及运算符优先级的问题。本话题将详细介绍如何使用C语言通过栈来实现一个...
在本项目中,“利用栈原理实现简易四则运算计算器”涉及到以下几个关键知识点: 1. **栈(Stack)**:栈是一种线性数据结构,其中元素的添加和删除操作(称为压入和弹出)只在栈顶进行。栈的基本操作包括压栈(push...
在C语言中,实现带括号的四则运算是一项基础且重要的编程任务,它涉及到解析字符串、处理运算优先级和栈数据结构等概念。在这个项目中,我们将使用Visual Studio作为集成开发环境,来编写和调试C语言代码。下面将...
本主题将探讨如何使用栈这种数据结构来实现一个支持四则运算与括号的计算器,主要使用C++语言进行编写。栈是一种具有“后进先出”(LIFO)特性的数据结构,非常适合处理具有运算顺序的表达式。 首先,我们需要理解...