最近在看数据结构的栈,其中有一节为栈应用到算术表达式的计算,接下来我讲举例说明如何用栈去计算,如有不对的地方,请各位大神指教。
1、定义操作符的优先级,”(“作为栈顶操作符时优先级仅高于”=”,”)”作为栈顶操作符时优先级是最高的,”*”和”/”优先级一样,但是一个作为栈顶的一个作为当前的操作符,那么栈顶的操作符的优先级就大于当前的操作符的优先级,”+”和”-“类似,但”+”和”-“无论是栈顶还是当前的优先级都小于”*”和”/”;
2、解析算术表达式。将算术表达式由字符串解析成每个元素;
3、扫描算术表达式,如果当前元素是操作数,则直接进操作数栈,如果当前元素是操作符,则从右操作符优先级列表中找到该操作符的优先级currentRank,并从左操作符优先级列表中找到栈顶操作符的优先级topRank,如果当前操作符优先级高于栈顶操作符优先级则当前扫描到的操作符直接进操作符栈;如果当前操作符优先级低于栈顶操作符优先级,则判断当前操作符是否为”)”,如果不为”)”,则栈顶操作符出栈,并且操作数栈先后出栈顶两个操作数,并利用出栈的操作符计算结果,并将结果压入操作数栈中,一直到当前操作符的优先级高于栈顶操作符的优先级截止,然后将当前操作符压入操作符栈中;如果为”)”,则栈顶操作符出栈,并且操作数栈先后出栈顶两个操作数,并利用出栈的操作符计算结果,并将结果压入操作数栈中,一直到栈顶操作符为”(“截止,然后将”(“出栈。
4、当算术表达式扫描完成之后,依次将操作符栈栈顶操作符出栈,并在同时将操作数栈栈顶两个操作数相继出栈,计算结果,将结果压入操作数栈中。
以上是整个计算步骤,下面是我自己编写的java程序。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class Stack {
private static LinkedList<String> operandStack; //操作数栈,静态成员函数里的成员变量必须为static
private static LinkedList<String> operatorStack; //操作符栈
private static Map<String, Integer> operatorLRank; //左操作符优先级
private static Map<String, Integer> operatorRRank; //右操作符优先级
private static List<String> expList; //算术表达式列表
private static List<Integer> eTypeList; //每个元素的类型,0为数字,1为操作符
private static Set<Integer> indexSet; //操作符位置集合
public static void main(String[] args) {
String exp=”5*2^(14+2*2-6*3)-(8-9*2)*2″;
// String exp=”2-(14+2*2-6*3)*3″;
initStack();
initOperatorRanks();
analysis(exp);
scanExp();
System.out.println(“计算结果: “+operandStack.getLast());
}
/**
* 初始化栈
*/
private static void initStack(){
operandStack=new LinkedList<String>();
operatorStack=new LinkedList<String>();
operatorLRank=new HashMap<String, Integer>();
operatorRRank=new HashMap<String, Integer>();
expList=new ArrayList<String>();
eTypeList=new ArrayList<Integer>();
}
/**
* 初始化操作符等级
*/
private static void initOperatorRanks(){
//初始化左操作符,也就是作为栈顶操作符,由于加减是按从左到右的顺序计算的,所以”+”,”-“作为栈顶操作符时比扫描的优先级大
operatorLRank.put(“=”, 0);
operatorLRank.put(“(“, 1);
operatorLRank.put(“+”, 3);
operatorLRank.put(“-“, 3);
operatorLRank.put(“*”, 5);
operatorLRank.put(“/”, 5);
operatorLRank.put(“^”, 6);
operatorLRank.put(“)”, 7);
//初始化右操作符,作为当前扫描的操作符
operatorRRank.put(“=”, 0);
operatorRRank.put(“)”, 1);
operatorRRank.put(“+”, 2);
operatorRRank.put(“-“, 2);
operatorRRank.put(“*”, 4);
operatorRRank.put(“/”, 4);
operatorRRank.put(“^”, 6);
operatorRRank.put(“(“, 7);
}
/**
* 解析算术表达式
*/
private static void analysis(String exp){
//首先找出算术表达式中所有非数字的操作符,并记录位置
indexSet=new TreeSet<Integer>();
for(int i=0;i<exp.length();i++){
if(!isDigital(exp.charAt(i))){
indexSet.add(i);
}
}
//遍历set将两个位置中的数字取出
Iterator<Integer> it=indexSet.iterator();
int endIndex=it.next();
if(!exp.substring(0, endIndex).isEmpty()){
expList.add(exp.substring(0, endIndex));
eTypeList.add(0);
}
while(it.hasNext()){
int beginIndex=endIndex;
endIndex=it.next();
expList.add(String.valueOf(exp.charAt(beginIndex)));
eTypeList.add(1);
String digital=exp.substring(beginIndex+1, endIndex);
if(!digital.isEmpty()){
expList.add(digital);
eTypeList.add(0);
}
}
expList.add(String.valueOf(exp.charAt(endIndex)));
eTypeList.add(1);
if(!exp.substring(endIndex+1, exp.length()).isEmpty()){
expList.add(exp.substring(endIndex+1, exp.length()));
eTypeList.add(0);
}
}
/**
* 判断字符是否为数字
* @param ch
* @return
*/
private static boolean isDigital(char ch){
//0的ascii是48,9的ascii是57
if(ch>=48 && ch<=57){
return true;
}else{
return false;
}
}
private static void scanExp(){
pushStack(operatorStack, “=”); //首先将最低等级的=压入操作符栈中
for(int i=0;i<expList.size();i++){
String e=expList.get(i);
//如果是操作符
if(eTypeList.get(i)==1){
/**
* 比较当前操作符与栈顶操作符的优先级,如果当前操作符优先级高于栈顶,则直接入栈
* 如果小于,则栈顶操作符出栈,并且操作数栈出栈顶两个元素,进行计算,并入栈,
* 直到当前操作符的优先级高于栈顶的优先级
*/
int currentRank=operatorRRank.get(e);//从右操作符栈中找出当前操作符的优先级
String topE=getStackTop(operatorStack);
int topRank=operatorLRank.get(topE);//从左操作符栈中找出栈顶操作符的优先级
//如果当前操作符大于栈顶操作符
if(currentRank>topRank){
pushStack(operatorStack, e);
}else{
if(!”)”.equals(e)){
while(currentRank<topRank){
computePush(topE);
topE=getStackTop(operatorStack);
topRank=operatorLRank.get(topE);//从左操作符栈中找出栈顶操作符的优先级
}
pushStack(operatorStack, e);
}else{
while(!”(“.equals(topE)){
computePush(topE);
topE=getStackTop(operatorStack);
topRank=operatorLRank.get(topE);//从左操作符栈中找出栈顶操作符的优先级
}
outStack(operatorStack); //将”(“出栈
}
}
}
//如果是操作数
else if(eTypeList.get(i)==0){
pushStack(operandStack, e);
}
print(operatorStack, operandStack);
}
//当扫描完成之后将操作符栈和操作数栈全部出栈
Iterator<String> it=operatorStack.iterator();
while(it.hasNext()){
String topE=getStackTop(operatorStack);
if(!”=”.equals(topE)){
computePush(topE);
}else{
break;
}
}
print(operatorStack, operandStack);
}
/**
* 操作数压栈
*/
private static void pushStack(LinkedList<String> stack, String e){
stack.addLast(e);
}
/**
* 操作数出栈
*/
private static void outStack(LinkedList<String> stack){
stack.removeLast();
}
/**
* 得到栈顶元素
* @param stack
*/
private static String getStackTop(LinkedList<String> stack){
return stack.getLast();
}
/**
* 如果当前操作符优先级小于栈顶优先级则栈顶操作符出栈,操作数栈出栈顶的两个元素并计算结果
* @param topE
*/
private static void computePush(String topE){
outStack(operatorStack); //操作符出栈顶元素
String e1=getStackTop(operandStack);
outStack(operandStack);
String e2=getStackTop(operandStack);
outStack(operandStack);
int res=compute(e2, topE, e1);
pushStack(operandStack, String.valueOf(res));
}
/**
* 计算两个元素的算术结果
* @param e1
* @param operator
* @param e2
* @return
*/
private static int compute(String e1, String operator, String e2){
int ie1=Integer.valueOf(e1);
int ie2=Integer.valueOf(e2);
if(“+”.equals(operator)){
return ie1+ie2;
}else if(“-“.equals(operator)){
return ie1-ie2;
}else if(“*”.equals(operator)){
return ie1*ie2;
}else if(“/”.equals(operator)){
return ie1/ie2;
}else if(“^”.equals(operator)){
return (int)Math.pow(ie1, ie2);
}else{
return 0;
}
}
private static void print(List list1, List list2){
for(int i=0;i<list1.size();i++){
if(i>0){
System.out.print(“,”);
}
System.out.print(list1.get(i));
}
for(int i=0;i<30-list1.size();i++){
System.out.print(” “);
}
for(int i=0;i<list2.size();i++){
if(i>0){
System.out.print(“,”);
}
System.out.print(list2.get(i));
}
System.out.println();
}
}