堆栈的应用:四则表达式运算

堆栈的经典应用,四则表达式的元算。这里只能操作的符号是:+ - * / ()。不支持大括号...

下面是代码:

package net.itaem.test;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

/**
 * 堆栈的应用
 * 使用这个堆栈完成四则表达式的运算 四则:+ - * //
 * 比如:3 + (15-1)*2 -10 = 21
 * */
public class StackApply {

	//四则表达式,也就是中缀表达式
	private String source;

	//程序不验证输入的表达式是否合法,所以请保证输入的表达式有效,否则计算结果可能无效
	//要求结果的四则表达式
	public StackApply(String source){

		if(source == null || "".equals(source)) throw new RuntimeException("输入的表达式不能为空");

		this.source = source;
	}

	//将中缀表达式变成后缀表达式
	public List<String> toLaterPattern(){
		//定义一个堆栈,用来保存操作符号
		Stack<Character> calStack = new Stack<Character>();

		//定义一个顺序表,用来存储表达式中的数字
		List<Integer> intList = new LinkedList<Integer>();

		//后缀表达式的最后结果
		List<String> resultList = new ArrayList<String>();

		//取出中缀表达式里面的全部数字
		String[] intArrays = source.split("[^0-9]");

		//将数字添加到集合中,并且去掉空值
		for(String intArray: intArrays){
			if(!"".equals(intArray)){
				intList.add(Integer.parseInt(intArray));
			}
		}

		int index = 0;

		int fromIndex = 0;

		//遍历后缀表达式
		for(int i=0; i<source.length();){
			//如果是数字,将数字添加到后缀表达式中
			if(isNumber(source.charAt(i))){
				//添加数值到结果集
				resultList.add(intList.get(index) + "");
				//查看这个数值占用的位数
				int intLength = (intList.get(index) + "").length();
				//修改下一个i的值
				i = source.indexOf(intList.get(index) + "", fromIndex) + intLength;
				//记录下下一个数值的起始处
				fromIndex = i;
				index++;
			}
			//如果是 + - * / ( ) 这四个符号,进行进出站操作
			else if(isCalculator(source.charAt(i))){
				//如果是‘(‘,进入堆栈
				if(source.charAt(i) == ‘(‘){
					calStack.add(source.charAt(i));
					//弹出第一栈顶到第一个(之间的操作符号
				}else if(‘)‘ == source.charAt(i)){
					//将数字的内容出栈
					Character pop = null;
					//输出()之间的内容
					while((pop = calStack.pop()) != ‘(‘){
						char[] p = new char[1];
						p[0] = pop;
						//将出栈的内容添加到结果集中
						resultList.add(new String(p));
					}

				}else{   //这里处理 + - * /的情况
					//是* /
					if(source.charAt(i) == ‘*‘ || source.charAt(i) == ‘/‘){
						calStack.push(source.charAt(i));   //因为 * /的优先级比较高,直接压入堆栈之中
					}else if(source.charAt(i) == ‘+‘ || source.charAt(i) == ‘-‘){
						//判断堆栈里面的内容,看看优先级关系
						if(calStack.isEmpty()){   //如果为空,直接添加进去堆栈之中
							calStack.push(source.charAt(i));
						}else{
							//取出第一个运算符号,这里不是弹出
							char pop = calStack.peek();
							//查看是否是优先级比较高的符号
							if(pop == ‘*‘ || pop == ‘/‘){
								while(!calStack.isEmpty()){    //输出所有优先级比较高的运算符
									pop = calStack.pop();

									if(pop == ‘*‘ || pop == ‘/‘){  //如果是 * /,优先级比较高,压入到堆栈中
										resultList.add(pop + "");
									}else{   //优先级比较低,停止
										break;
									}
								}
								//弹出完成之后,要将此次的操作符添加到堆栈中
								calStack.push(source.charAt(i));
							}else{   //如果是相同优先级的+ -,添加到堆栈之中

								// 1-2-3-4不满足结合律,所以要特殊处理,将数字改变为负数
								if(source.charAt(i) == ‘-‘ && pop == ‘-‘){
									resultList.set(index-1, -intList.get(index-1) + "");
								}

								calStack.push(source.charAt(i));
							}
						}
					}

				}
				i++;
			}
		}

		//将堆栈里面所有的操作符号取出来
		List<String> pops = new LinkedList<String>();
		while(!calStack.isEmpty()){
			pops.add(calStack.pop()+"");
		}

		for(String pop: pops){
			resultList.add(pop);
		}

		return resultList;

	}

	public String each(char c){
		return null;
	}

	private boolean isCalculator(char c) {
		switch(c){
		case ‘+‘:
		case ‘-‘:
		case ‘*‘:
		case ‘/‘:
		case ‘(‘:
		case ‘)‘:return true;

		default:return false;
		}
	}

	//判断一个字符是否是数字
	private boolean isNumber(char c) {
		switch(c){
		case ‘0‘:
		case ‘1‘:
		case ‘2‘:
		case ‘3‘:
		case ‘4‘:
		case ‘5‘:
		case ‘6‘:
		case ‘7‘:
		case ‘8‘:
		case ‘9‘:return true;
		default:return false;
		}
	}

	//返回计算结果
	public float result(){
		//得到后缀运算表达式的内容
		List<String> laterPattern = toLaterPattern();

		//用来保存计算结果的堆栈
		Stack<Float> floatStack = new Stack<Float>();

		float calResult = 0;

		//计算结果
		//计算过程:如果是数字,进堆栈,如果是运算操作符,出栈,然后执行运算,再将运算结果压入堆栈
		for(String c: laterPattern){
			if(c.matches("-?\\d+")){    //将数字取出来,然后压入堆栈中
				//将数字压入到堆栈中
				floatStack.push(Float.parseFloat(c));

			}else{
				//取出两个操作数
				float first = floatStack.pop();
				float second = 0;

				//处理是负数的情况
				if(!floatStack.isEmpty()){
					second = floatStack.pop();
				}

				char choose = c.toCharArray()[0];
				switch(choose){
				case ‘+‘:
					calResult = second+first;
					break;
				case ‘-‘:
					//2-(-2)==4,所以这里要特殊处理
					if(first > 0){
						calResult = second - first;

					}else{
						calResult = second + first;
					}
					break;
				case ‘*‘:
					calResult = second*first;
					break;
				case ‘/‘:
					calResult = second/first; //记得转为float,避免出现 3/2 == 1的情况
					break;
				default:throw new RuntimeException("操作符有错误...目前暂且不支持+ - * / ( ) 之外的运算符");
				}

				//将计算结果压入堆栈
				floatStack.push(calResult);
			}
		}

		//最后一个栈顶元素就是结果
		return floatStack.pop();
	}

	public static void main(String[] args) {
		System.out.println("1+2+3+4 = " + new StackApply("1+2+3+4").result());
		System.out.println("1+2+3*4 = " + new StackApply("1+2+3*4").result());
		System.out.println("(-11)+2+3*4 = " + new StackApply("(-11)+2+3*4").result());
		System.out.println("11+2/3*4 = " + new StackApply("11+2/3*4").result());
		System.out.println("1*2*3*4 = " + new StackApply("1*2*3*4").result());
		System.out.println("1/(2/(3/4)) = 1/2/3/4 = " + new StackApply("1/2/3/4").result() + " = " + new StackApply("1/2/3/4").result());   //相当于是 1/(2/(3/4))
		System.out.println("1+2*3-1 = " + new StackApply("1+2*3-1").result());
		System.out.println("1-2-3-4 = " + new StackApply("1-2-3-4").result());

	}

}

上面的代码可能有点乱,不过主要的思想就是堆栈的应用

运算结果:

1+2+3+4 = 10.0
1+2+3*4 = 15.0
(-11)+2+3*4 = 3.0
11+2/3*4 = 11.166667
1*2*3*4 = 24.0
1/(2/(3/4)) = 1/2/3/4 = 0.375 = 0.375
1+2*3-1 = 5.0
1-2-3-4 = -8.0

总结:堆栈是一个FIRST IN LAST OUT,典型的FILO的数据结构。在计算机中,应用很广泛,大家可以认真研究下...

时间: 2024-08-28 19:16:19

堆栈的应用:四则表达式运算的相关文章

C语言写的秒速计算四则混合运算项目

开发语言:C语言 开发工具:Visual Studio 2017 整理时间:2017年8月2日 源代码:500行: 开发方式:C语言多文件模式开发 实现功能:在文件中写入四则混合运算表达式(无论有多长...),按运行即可得出结果. 四则混合运算表达式形如: (19+67)*33-45/5+17*52+39/3+.... 意义:在实际快速计算的同时,对学习也有如下意义:对堆栈的学习应用,多多文件的学习巩固 项目演示截图: 其他C语言项目参考:

MathExamV2.0四则混合运算计算题生成器

MathExamV2.0四则混合运算计算题生成器----211606360 丁培晖 211606343 杨宇潇 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 ? Estimate ? 估计这个任务需要多少时间 60 100 Development 开发 ? Analysis ? 需求分析 (包括学习新技术) 360 440 ? Design Spec ? 生成设计文档 20 20 ? D

软件工程学习之小学四则混合运算出题软件 Version 1.00 设计思路及感想

对于小学四则混合运算出题软件的设计,通过分析设计要求,我觉得为了这个软件在今后便于功能上的扩充,可以利用上学期所学习的<编译原理>一课中的LL1语法分析及制导翻译的算法来实现.这样做的好处有以下几点: 1. 由于LL1制导翻译是一项成熟且可靠的技术,并且其递归下降算法易于改编为算式生成算法: 2. 我们有系统的方法可以获得较复杂表达式的LL1文法,则可以方便地生成形式丰富的算式: 3.由于四则混合运算中需要考虑运算优先级的问题,那么采用LL1分析器可以很方便的实现计算表达式的功能: 4.当用户

基于MFC的含四则混合运算的计算器

今天无意间发现win7系统的标准型计算器连最基本的四则混合运算都没做,刚刚好公司给了我一个工作任务,就是用MFC实现一个含四则混合运算的计算器. 我在网上查询资料,发现大部分只是实现了基本的加减乘除运算,而含四则混合运算的也没有能够说得清楚明白.于是我搜索四则混合运算算法,发现要实现四则混合运算,就要用到逆波兰算法,而使用逆波兰算法,就要先把算术式从中缀表达式转换为后缀表达式. 所谓中缀表达式,就是我们平常的算术式,例如:1+2-3*4/5. 而后缀表达式,就是将运算符写在操作数之后,上面算术式

JAVA实现简单四则混合运算

JAVA实现简单四则混合运算,说明:该计算器支持实则混合运算,如 2*(3+1 )/ 4-3 *9+ 8/ 3*4- 5,则输出:-19.333332 需要说明的事括号必须是英文的.源码如下仅供学习: 运行后直接在Console里面敲然后回车即可 [1].[代码] [Java]代码 跳至 [1] ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

第四次作业 结对编程 (四则混合运算)

一 需求分析 本次我们做的程序是数学的四则混合运算,并且增加了部分人性化的功能,接下来,我们谈谈这个程序的相关需求,此程序是一个1—10的四则混合运算,那么可以想到主要用于小学生,(ps 个人想法,不排除其他高年级的使用,因为用户可以输入任意的随机数范围),此外,本程序还可能会出现在家庭.教育机构和部分教学网站上面,因为他们可能会给学生出一些简单的数学题目,可以自由设置测试时间,题目数量等内容,而这一程序正好解决了这一个问题,我想,产品的需求必须首先知道用户需要什么,要以客户为中心.而这个产品正

栈的应用——四则表达式求值

栈的应用有很多,四则运算是一个比较常见的应用.对于四则运算,括号内的要先运算,而且还要先乘除后加减,又要涉及到负数和浮点数,看上去简简单单的式子,其实暗藏杀机. 常用的方法是利用后缀表达式(逆波兰)进行计算.主要分为两步: (1)将中缀表达式转化为后缀表达式(栈用来进出运算的符号): 从左到右遍历中缀表达式的每一个数字和符号,若是数字就输出,既成为后缀表达式的一部分,若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减),则栈顶元素依次出栈并输出,并将当前符号进栈,一

C#实现将字符串作为表达式运算

转载:http://blog.csdn.net/lifeforcode/article/details/2010807 曾经有个需求,要把一段字符串作为C#的一段语句来执行.说实在了,就类似实现计算器的功能,把用户输入的数据作为运算式来执行,当时的需求当然不这么简单,不过在解决思路上没 区别.       队友们提出了几个方案,第一个方案是强技术型的:把这个字符串解析成波兰式,再把这个波兰式压入队列中逐步处理.第二个方案是强工具型的:利用数据库的运算功能,把这个字符串组成Sql交给数据库运算.最

算法学习记录-栈的应用--表达式运算

前面做了栈的基本操作 总感觉需要做一个实际的例子来检验一下. 这里我将用栈来做一个简单的四则运算. 目标比较简单: 做一个带小括号(“()”)的四则运算,如果要加入到中括号(“[]”)或者大括号(“{}”),依次类推. 求一个表达式: 用下面这个算是做例子,程序最后应该可以算出任何带小括号的运算. 3+(32-6)*9+5*3-(3*(65-15)/5)+12; 方法一:后缀法. 1.了解中缀和后缀表示法 中缀表示法:刚才的那个算是就是中缀表示法,我们通常看到的数学符号就是中缀表示法,即数字在计