相关介绍:

 一种求解字符串形式的表达式的结果的算法,该算法在求解时,需要先将我们平日里习惯上使用的中序表达式的模式转化为等价的后序(后缀)表达式的模式,之后再通过求解出该后序(后缀)表达式的结果而得到原中序表达式的结果,为此,该算法主要有两个任务。第一是将中序表达式转化为后序(后缀)表达式的形式。第二是通过求解后序(后缀)表达式的结果,从而得到原中序表达式的结果。

 所谓的中序表达式,就是将运算符放在两个操作数的中间,就是我们平日里所使用的算数表达式的形式,如:1+2+(34+1)*23,10-2等,而后序表达式就是将运算符放在两个操作数之后,如中序表达式A+(B-C/D)*E对应的后序(后缀表达式)为ABCD/-E*+。由于运算符有优先级,为此在计算机内部使用中序表达式来描述时,对计算是非常不方便的,特别是带括号时更加麻烦。而后序表达式中既无运算符优先级,又无括号的约束问题因此在后序表达式中运算符出现的顺序正是计算的顺序,所以计算一个后序表达式比计算一个中序表达式的值简单得多。

中序表达式转化为后序表达式:

 由于中序表达式与后序表达式中的操作数所出现的先后次序是完全一样的,只是运算符出现的先后次序不同,为此,将中序表达式转化为后序表达式,其重点是放在运算符的处理上。首先设定运算符的优先级如下表所示:

运算符 +(加)、-(减) *(乘)、/(除)
优先级 1 2

其中,其数值越大的表示其运算符的优先级越高。

 要使其运算符出现的次序与真正的算术运算符顺序一致,就要使优先级高的以及括号内的运算符先出现在前面,所以在把算术表达式转化为后序表达式的时候,要使用一个栈来保留还未送往后缀表达式的运算符,此栈称为运算符栈。其算法的基本思想如下:

  1. 初始化一个运算符栈
  2. 从算术表达式输入的字符串中从左到右读取一个字符
  3. 若当前字符是操作数,则直接送往后缀表达式
  4. 若当前字符是左括号“(”,则将其压入运算符栈
  5. 若当前字符为运算符时,则
    1. 当运算符栈为空时,将该运算符直接压入运算符栈中
    2. 当此运算符的优先级高于栈顶元素时,将此运算符压入运算符栈;否则,弹出栈顶运算符送往后序表达式,并将当前运算符压栈,重复步骤5
  6. 若当前字符是右括号")"时,反复将栈顶符号弹出,并送往后序表达式,直到栈顶运算符为左括号"("为止,再将左括号出栈并丢弃
  7. 若读取未完成,则跳转到步骤2
  8. 若读取完毕,则将栈中剩余的所有运算符弹出栈,并送往后序表达式中

其实现代码如下:

public class ReverseBoLan
{
//该符号表用于定义运算符的优先级
private Map<String,Integer> table=getMap();
//该字符串为用于匹配数字的正则表达式
private String rexNumber="\\d+";
private String rexOperator="[((+\\-*/×÷))]";
//该字符串为用户输入的中序表达式
private String input;
//该栈对象用于存储运算符和括号(左括号)
private Stack<String> save=new Stack<String>();
/**
* 该方法用于将中序表达式转化为后序表达式,并对其转化后的表达式以字符串的形式进行返回
* @return 后序表达式
*/
public String reverse()
{
//result变量用于存储结果
String result="";
//将输入的中序表达式中的数字存储到number数组中
String[] number=input.split(rexOperator);
int order=0;
int i=0;
while(i<input.length())
{
//获得当前字符
String thisString=String.valueOf(input.charAt(i));
//当前该字符为运算符或者括号时,即当前该字符不为数字时
if(thisString.matches(rexOperator))
{
//当当前字符不为左括号或者右括号时(即为运算符)
if(!thisString.matches("[()()]"))
{
//用于记录栈顶元素的优先级
int temporary=0;
//获取当前字符的优先级
int present=table.get(thisString);
//当操作数的栈不为空的时候
if(!save.isEmpty())
{
//查看栈顶元素的字符以及其优先级
String top=save.getTop();
if(!top.matches("[((]"))
{
temporary=table.get(top);
}
}
//当栈顶元素的操作符的优先级比当前操作符的优先级还要高或者相同时,对其进行弹出操作,直到栈顶元素的优先级比当前操作符的优先级要低
if(temporary>=present)
{
while(!save.isEmpty()&&table.get(save.getTop())>=present)
{
result+=" "+save.pop();
}
}
save.push(thisString);
}
//当当前的字符为左括号的时候,直接将其压入栈中
else if(thisString.matches("[((]"))
{
save.push(thisString);
}
//当当前的字符为右括号的时候,将其栈中的元素一直弹出,直至遇到左括号结束,并将左括号弹出
else
{
while(!save.getTop().matches("[((]"))
result+=" "+save.pop();
save.pop();
}
i++;
}
//当前该字符为数字的时候
if(thisString.matches(rexNumber))
{
//用于存储数字数组中的数字字符串
String numberString=null;
do
{
numberString=number[order];
//当数字字符串中的数字不为空时(由于可能会是空字符串的出现),将整个中序表达式的字符串的指针进行向右移动
if(!numberString.trim().equals(""))
{
i+=numberString.length();
order++;
break;
}
else
{
order++;
}
}while(true);
result+=" "+numberString;
}
}
//将栈中剩余的字符进行弹出
while(!save.isEmpty())
{
result+=" "+save.pop();
}
return result;
}
/**
* 该方法用于设置实例变量input的值
* @param input 为中序表达式
*/
public void setInput(String input)
{
//去掉输入的字符串中存在的所有的空字符
input=input.replaceAll(" ", "");
//去掉中序表达式字符串中各种杂七杂八的字符
input=input.replaceAll("[^+\\-*/×÷\\.\\d()()]", "");
this.input=input;
} //该方法用于实现一个符号表
private static Map<String,Integer> getMap()
{
Map<String,Integer> temp=new HashMap<String,Integer>();
//定义各个运算符的优先级,其中,x和÷字符用于兼容
temp.put("*", 2);
temp.put("/", 2);
temp.put("×",2);
temp.put("÷",2);
temp.put("+", 1);
temp.put("-",1);
return temp;
}
}

计算后序表达式的结果:

 计算一个后序表达式的值比较简单,只要先找到运算符,再去找前面最后出现的两个操作数,从而构成一个较小的算术表达式进行运算,在计算过程中,也需要利用一个栈来保留后序表达式中还未参与运算的操作数,此栈称之为操作数栈。计算后序表达式值的算法的基本实现如下:

  1. 初始化一个操作数栈
  2. 从左到右依次读入后序表达式中的字符:
    1. 若当前字符是操作数,则压入操作数栈中
    2. 若当前字符是运算符,则从栈顶弹出两个操作数并分别作为第2个操作数和第1个操作数参与运算,再将运算结果压入操作数栈中
  3. 重复步骤2,直到读入的后序表达式结束为止,则操作数栈中的栈顶元素即为后序表达式的计算结果

其实现的关键代码如下:

/**
* 该方法用于将后序表达式的结果进行计算,得出其最终结果
* 返回最终计算的结果。
* 输入的参数为前面带空格的,数字和运算符之间带空格的后序表达式
*
*/ public double counter(String input)
{
//去掉其首尾空格
input=input.trim();
//该栈用于存储下数字
Stack<String> numbers=new Stack<String>();
//用于记录下数字使用
String n="";
//用于循环遍历每一个字符
for(int i=0;i<input.length();i++)
{
String ch=String.valueOf(input.charAt(i));
//当前的字符为空字符的时候,遍历下一个字符
if(ch.equals(" "))
{
//将数字字符串存入栈中并遍历下一个字符
numbers.push(n);
n="";
continue;
}
//当为数字的时候,对其进行组装,将其组装成字符串
else if(ch.matches("[0-9\\.]"))
{
n+=ch;
}
//当其为运算符的时候,对其栈中的前两个数字字符串进行弹出,并将运算结果压入栈中
else
{
switch(ch)
{
case "×":
case "*":
{
double two=Double.parseDouble(numbers.pop());
double one=Double.parseDouble(numbers.pop());
double result=one*two;
n=String.valueOf(result);
break;
}
case "÷":
case "/":
{
double two=Double.parseDouble(numbers.pop());
double one=Double.parseDouble(numbers.pop());
double result=one/two;
n=String.valueOf(result);
break;
}
case "+":
{
double two=Double.parseDouble(numbers.pop());
double one=Double.parseDouble(numbers.pop());
double result=one+two;
n=String.valueOf(result);
break;
}
case "-":
{
double two=Double.parseDouble(numbers.pop());
double one=Double.parseDouble(numbers.pop());
double result=one-two;
n=String.valueOf(result);
break;
}
}
}
}
//将最后计算的结果放入栈中
numbers.push(n);
double result=Double.parseDouble(numbers.pop());
return result;
}

回到目录|·(工)·)

K:逆波兰算法的更多相关文章

  1. C++ | 栈的应用(逆波兰算法) | 计算器

    #include <iostream> using std::cin; using std::cout; using std::endl; template<typename T&g ...

  2. 算法--链表的K逆序问题

    转载请标明出处http://www.cnblogs.com/haozhengfei/p/9e6f4dda3138cf9fab17f996ec85b624.html 链表的K逆序问题     链表的k逆 ...

  3. shunting-yard 调度场算法、中缀表达式转逆波兰表达式

    中缀表达式 1*(2+3) 这就是一个中缀表达式,运算符在数字之间,计算机处理前缀表达式和后缀表达式比较容易,但处理中缀表达式却不太容易,因此,我们需要使用shunting-yard Algorith ...

  4. leetcode算法学习----逆波兰表达式求值(后缀表达式)

    下面题目是LeetCode算法:逆波兰表达式求值(java实现) 逆波兰表达式即后缀表达式. 题目:  有效的运算符包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰表达式.同 ...

  5. 代码随想录第十三天 | 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素

    第一题150. 逆波兰表达式求值 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 注意 两个整数之间的除法只保留整数部分. ...

  6. C++基础算法学习——逆波兰表达式问题

    例题:逆波兰表达式逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3.逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 ...

  7. ACM -- 算法小结(六)逆波兰表达式

     逆波兰表达式 //问题描述:逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2+3的 //逆波兰表达式法为+ 2 3.逆波兰表达式的优点是运算符之间不必有优先级关系,也不必 //用括号改 ...

  8. C#数据结构与算法系列(十):逆波兰计算器——逆波兰表达式(后缀表达式)

    1.介绍 后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后 2.举例说明 (3+4)*5-6对应的后缀表达式就是3 4 +5 * 6 - 3.示例 输入一个逆波兰表达式(后缀表达 ...

  9. noi1696 逆波兰表达式

    1696:逆波兰表达式 http://noi.openjudge.cn/ch0303/1696/ 总时间限制:  1000ms 内存限制:  65536kB 描述 逆波兰表达式是一种把运算符前置的算术 ...

随机推荐

  1. [CSS3] :nth-child的用法

    :nth-child(2)选取第几个标签,“2可以是你想要的数字” .demo01 li:nth-child(2){background:#090} :nth-child(n+4)选取大于等于4标签, ...

  2. [Flex] 组件Tree系列 —— 打开和关闭节点

    mxm: <?xml version="1.0" encoding="utf-8"?> <!--功能描述:打开和关闭节点--> < ...

  3. 由一个场景分析Mysql的join原理

    背景 这几天同事写报表,sql语句如下 select * from `sail_marketing`.`mk_coupon_log` a left join `cp0`.`coupon` c on c ...

  4. QuantLib 金融计算——数学工具之求解器

    目录 QuantLib 金融计算--数学工具之求解器 概述 调用方式 非 Newton 算法(不需要导数) Newton 算法(需要导数) 如果未做特别说明,文中的程序都是 Python3 代码. Q ...

  5. solr 服务搭建

    1.  linux 中 安装jdk,  tomcat, 2. 下载 solr-4.10.3.tgz.tgz 并解压 解压后文件夹:solr-4.10.3 3. 将 solr-4.10.3/dist 下 ...

  6. selenium和appium启动的感悟

    阅读源码后整理记录如下: selenium : 1.若为webdriver.Chrome()方式启动:①子程序打开chromedriver.exe程序,程序打开后,监听9515端口作为remote_s ...

  7. c#Task类。实现异步的一种方式

    Task和Task<TResult>是c#提供的一种实现异步功能的2个类.Task<TResult>继承Task类,有返回参数. 1.基本用法 不嵌套利用静态方法创建和运行任务 ...

  8. eclipse常用快捷键实践积累

    1. [Ctrl + D]:删除一整行 2. 给函数添加注释 [选中函数名]-[Alt + Shift + J].如果需要自定义注释内容可通过[项目]-[属性]-[Java代码样式]-[代码模板]-[ ...

  9. Android多媒体之view,SurfaceView,GLSurfaceView

    1.相关概念 不用画布,直接在窗口上进行绘图叫做无缓冲绘图. 用了一个画布,将所有内容都先画到画布上,在整体绘制到窗口上,就该叫做单缓冲绘图, 那个画布就是一个缓冲区.用了两个画布,一个进行临时的绘图 ...

  10. 控制反转(IOC) 和依赖注入(DI) 的理解

    1.      IOC(控制反转) inverseof control是spring容器的内核,AOP.声明事务等功能在此基础上开花结果. 2.      通过实例理解IOC概念: 实例:<墨攻 ...