【数据结构】栈的应用之表达式计算器

表达式计算器是数据结构书籍里面的一个有趣的例子,感觉这里面已经有点编译原理的味道了,它利用栈来实现表达式的计算。它的基本思路是:初始化两个栈,一个是运算符栈,一个是运算数栈。把输入的字符串扫描一遍,遇到数字字符就把它拼成数字,遇到运算符就判断优先级,如果运算符栈中的优先级比较高,就把运算数栈中的数字弹出栈,与扫到的数字运算并压到运算数栈。如果运算符栈中的优先级比较低,就压栈,继续扫描。直到最后扫描完毕,从运算数栈中取出结果。



package main;
import java.util.*;
import java.io.*;

//=============================
//栈的应用之表达式计算器
//作者:落叶似秋
//日期:2015.7.27
//=============================
public class Main
{
	public static void main(String[] args)
	{
		String str=null;
		System.out.println("\n**请输入表达式,以等号结束**");
		Scanner scan=new Scanner(System.in);
		if(isReasonable(str=scan.next()))
		{
			System.out.println(clearZero(computer(str)));
		}
		else
		{
			System.out.println("表达式不合法");
			
		}
		
		main(null);
	}

	//去掉后面多余的点和零
	private static String clearZero(String str)
	{
		if(str.endsWith(".0"))
		{
			str=str.substring(0,str.length()-2);
		}
		return str;
	}
	//简单验证表达式
	private static boolean isReasonable(String str)
	{
		if(str.length()<=0||!str.endsWith("="))
			return false;
		int zn=0;
		int yn=0;
		char ch=0;
		for(int i=0;i opendStack=new MStack();
		//存储运算符
		MStack oprStack=new MStack();

		char ch=0;
		//开始先往栈压人#号
		oprStack.push('#');
		//临时存储运算数的字符串形式
		String num="";
		int i=0;
		
		//栈空了,或者ch=='#',才不继续循环
		while (ch != '=' || oprStack.peek() != '#')
		{
			//判断是否是运算符
			if (isOpr(ch))
			{
				
				if (num.length() != 0)
				{
					opendStack.push(num);
					//清空字符串
					num = "";
				}
				
				switch (getPrecede(oprStack.peek(), ch))
				{
					case '>':
						//大于说明栈内的表达式优先级比较高
						//就把他们退栈并先计算再把结果压栈
						
						char opr=oprStack.pop();
						//把先出栈的作为第二个参数来计算
						String num2=opendStack.pop();
						String num1=opendStack.pop();
						opendStack.push(operate(num1, opr, num2));
						break;
					case '<':
						oprStack.push(ch);
						//获取表达式的下一个字符,下同
						ch = str.charAt(i++);
						break;
					case '=':
						//当ch和oprStack.peek()的优先级相等说明出现一对括号或者运算完毕
						//就把运算符栈里的运算符弹出栈
						oprStack.pop();
						ch = str.charAt(i++);
						break;
				}
			}
			else
			{
				//如果读到运算数或者小数点,就把他拼成数
				num += ch;
				ch = str.charAt(i++);
			}
			
		}

		return opendStack.peek();
	}


	/*
	 * 判断运算符的优先级(s是否小于c)
	 * @s  第一个出现的运算符
	 * @c 第二个出现的运算符
	 * 解释:当第一个字符和第二个字符是相同,并且他们是加减乘除中的运算符
	 * 那么ch1优先级是大于ch2的,因为表达式从左往右运算
	 */
	private static char getPrecede(char s, char c)
	{
		switch (s)
		{
			case '+':
			case '-':
				if (c == '+' || c == '-')
					return '>';
				else if (c == '*' || c == '/')
					return '<';
				else if (c == '(')
					return '<';
				else if (c == ')')
					return '>';
				else
					return '>';
			case '*':
			case '/':
				if (c == '+' || c == '-')
					return '>';

				else if (c == '*' || c == '/')
					return '>';
				else if (c == '(')
					return '<';
				else if (c == ')')
					return '>';
				else
					return '>';
			case '(':
				if (c == '+' || c == '-')
					return '<';
				else if (c == '*' || c == '/')
					return '<';
				else if (c == '(')
					return '<';
				else if (c == ')')
					return '=';
				else
					return 'E';
			case ')':
				if (c == '+' || c == '-')
					return '>';
				else if (c == '*' || c == '/')
					return '>';
				else if (c == '(')
					return 'E';
				else if (c == ')')
					return '>';
				else
					return '>';
			case '#':
				if (c == '+' || c == '-')
					return '<';
				else if (c == '*' || c == '/')
					return '<';
				else if (c == '(')
					return '<';
				else if (c == ')')
					return 'E';
				else
					return '=';
			default:
				break;
		}
		return 0;
	}

	/*
	 * 判断是不是运算符
	 * */
	private static boolean isOpr(char ch)
	{
		final String opr="+-*/()#=";
		if (opr.contains(String.valueOf(ch)))
			return true;
		else
			return false;
	}

	/*
	 * 计算两个数之间的运算
	 * @x 第一个数
	 * @opr 运算符
	 * @y  第二个数
	 */
	private static String operate(String x, char opr, String y)
	{
		double result;
		double x1=Double.parseDouble(x);
		double y1=Double.parseDouble(y);
		switch (opr)
		{
			case '+':
				result = x1 + y1;
				break;
			case '-':
				result = x1 - y1;
				break;
			case '*':
				result = x1 * y1;
				break;
			case '/':
				if (y1 == 0)
				{
					//零不能做分母
					return "0";
				}
				else
				{
					result = x1 / y1;
					break;
				}
			default:
				//其他错误
				return "0";
		}
		return String.valueOf(result);
	}

}

class MStack
{
	/*
	 *stack类
	 */
	private List list;
	private int top;

	public MStack()
	{
		list = new LinkedList();
		top = -1;//-1表示一个空栈
	}

	/*
	 *出栈
	 */
	public E pop() throws StackEmptyException
	{
		if (top != -1)
		{
			E e=list.get(top);
			list.remove(top);
			top--;
			return e;
		}
		else
			throw new StackEmptyException();

	}
	/*
	 *入栈
	 */
	public void push(E e)
	{
		list.add(e);
		top++;
	}

	/*
	 *取栈顶元素
	 */
	public E peek() throws StackEmptyException
	{
		if (top != -1)
			return list.get(top);
		else
			throw new StackEmptyException();
	}

	/*
	 *获取栈的长度
	 */
	public int length()
	{
		return top + 1;
	}
	/*
	 *清空栈
	 */
	public void clear()
	{
		list.clear();
		top = -1;
	}
}
/*
 * 栈为空时引发的异常
 */
class StackEmptyException extends RuntimeException
{
	public StackEmptyException()
	{
		super("Stack is Empty.");
	}
}


 
 

你可能感兴趣的:(算法/数据结构)