`
hellojyj
  • 浏览: 58843 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

用栈结构解析四则运算

阅读更多

对于四则运算大家都不陌生了吧!

相信能看懂这篇文章上字的人基本都会算四则运算。但是怎么让计算机去解析这个四则运算呢?

计算机只能计算+ - * / %  如果四则运算的表达式中出现括号,那又该怎么办呢?这里呢,就需要用到一定的数学知识了!我们书写的四则运算表达式一般是用中缀式(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();
	}

}

 

  • 大小: 288.4 KB
  • 大小: 200.2 KB
  • 大小: 224.6 KB
  • 大小: 224.6 KB
4
1
分享到:
评论

相关推荐

    栈的四则运算实现及详解

    c语言数据结构栈的四则运算(带括号)的实现,里面有解释

    数据结构课程设计-用栈实现表达式求值的方法详解

    利用算符优先关系,实现对算术四则混合运算表达式的求值。(1)输入的形式:表达式,例如2*(3+4) 包含的运算符只能有’+’ 、’-‘ 、’*’ 、’/’ 、'(‘、 ‘)’;(2)输出的形式:运算结果,例如2*(3+4)=14;...

    C语言实例解析精粹(第二版) 光盘代码

    108 递归整数四则运算 109 复平面作图 110 绘制彩色抛物线 111 绘制正态分布曲线 112 求解非线性方程 113 实矩阵乘法运算 114 求解线性方程 115 n阶方阵求逆 116 复矩阵乘法 117 求定积分 118 求满足特异条件的数列 ...

    C语言实例解析精粹

    108 递归整数四则运算 109 复平面作图 110 绘制彩色抛物线 111 绘制正态分布曲线 112 求解非线性方程 113 实矩阵乘法运算 114 求解线性方程 115 n阶方阵求逆 116 复矩阵乘法 117 求定积分 118 求满足特异...

    C 语言实例解析精粹(第二版)(书+盘)

    108 递归整数四则运算 109 复平面作图 110 绘制彩色抛物线 111 绘制正态分布曲线 112 求解非线性方程 113 实矩阵乘法运算 114 求解线性方程 115 n阶方阵求逆 116 复矩阵乘法 117 求定积分 118 求满足特异...

    C语言精粹(第2版)随书关盘

    108 递归整数四则运算 109 复平面作图 110 绘制彩色抛物线 111 绘制正态分布曲线 112 求解非线性方程 113 实矩阵乘法运算 114 求解线性方程 115 n阶方阵求逆 116 复矩阵乘法 117 求定积分 118 求满足特异...

    java设计模式

    27.1 四则运算你会吗 27.2 解释器模式的定义 27.3 解释器模式的应用 27.3.1 解释器模式的优点 27.3.2 解释器模式的缺点 27.3.3 解释器模式使用的场景 27.3.4 解释器模式的注意事项 27.4 最佳实践 第28章 享元模式 ...

    超级有影响力霸气的Java面试题大全文档

    如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。 18、error和exception有什么区别?  error 表示恢复...

    javascript入门笔记

    只做整数运算,如果是小数的话,则去掉小数位再运算 2、位运算 1、按位 与 :& 语法 :a & b 特点 :将 a 和 b 先转换为二进制,按位比较,对应位置的数字都为1的话,那么该位的整体结果为1,否则就为0 ex:5 ...

    java 面试题 总结

    如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。 15、error和exception有什么区别? error 表示恢复不是...

    世界500强面试题.pdf

    1.4.9. 栈的 push、pop 序列[数据结构] .......................................................... 99 1.4.10. 统计整数二进制表示中 1 的个数........................................................102 1.5....

Global site tag (gtag.js) - Google Analytics