JAVA数据结构及算法–解析算术表达式

1、本章内容主要参考于《Java数据结构和算法第二版》这本书。平时说的算术表达式就是中缀表达式,对计算机的算法来说如果要直接求算术表达式的值是比较困难的,所以可以按下面两步来实现算法会更容易:

  • 将算术表达式转换成另一种形式:后缀表达式。可以参考《中缀表达式转后缀表达式 》
  • 计算后缀表达式的值。会使用到栈的知识,可以参考《JAVA数据结构及算法–Stack应用 》

2、中缀表达式转后缀表达式逻辑图

java 解析运算规则_后缀表达式


3、中缀表达式转后缀表达式代码实现

package stack;
/**
 * 中缀表达式转换成后缀表达式
 */
public class InToPost {
	private StackE<String> stack;
	private String input;//输入中缀表达式
	private String output = "";//输出后缀表达式
	//加减(+-)的优先权
	private static final int PRECEDENCE_1 = 1;
	//乘除(*/)的优先权
	private static final int PRECEDENCE_2 = 2;
	
	public InToPost(String in){
		input = in;
		int stackSize = input.length();
		stack = new StackE<String>(stackSize);
	}
	//中缀表达式转换成后缀表达式
	public String doTrans(){
		for (int i = 0; i < input.length(); i++) {
			char ch = input.charAt(i);//中缀表达式中的字符
			stack.displayStack("For " + ch + " ");
			switch (ch) {
			case '+':
			case '-':	
				getOper(ch, PRECEDENCE_1);//判断加减(+-)号是入栈,还是直接添加到字符串output中
				break;
			case '*':
			case '/':
				getOper(ch, PRECEDENCE_2);//判断乘除(*/)号是入栈,还是直接添加到字符串output中
				break;
			case '(':
				stack.push(ch+"");//遇到的字符是左括号'(',就直接压入栈顶
				break;
			case ')':
				//将栈顶元素弹出栈并加入到字符串output中,直到弹出的元素是右括号')'为止,但是最后弹出的左括号不加入字符串output中
				getParen(ch);
				break;
			default:
				output += ch;
				break;
			}//end switch
		}//end for
		while (!stack.isEmpty()){
			stack.displayStack("while ");
			output += stack.pop();
		}
		stack.displayStack("End ");
		return output;
	}
	/**
	 * 操作符opThis是加减乘除时,通过跟栈顶元素opTop对比优先权,如果opThis的优先权大于opTop,
	 * 那么直接将opThis压入栈顶,否则先将opTop弹出栈顶,然后再将opThis压入栈顶
	 * @param opThis 输入的操作符
	 * @param prec1  opThis的优先权,1代表加减;2代表乘除
	 */
	public void getOper(char opThis, int prec1){
		while( !stack.isEmpty()){
			char opTop = stack.pop().charAt(0);//弹出了栈顶元素,如果opThis的优先权大于opTop,那么需要重新压入opTop到栈顶
			//如果栈顶元素是'(',那么重新压入刚弹出的栈顶元素'(',跳出循环并且将opThis直接压入栈顶
			if (opTop == '('){
				stack.push(opTop+"");
				break;
			}else{//如果栈顶元素是操作符,那么对比opThis跟opTop的优先权。
				int prec2;//用来保存栈顶元素opTop的优先权
				if (opTop == '+' || opTop == '-')
					prec2 = 1;//如果栈顶元素为操作符'+'或者'-',那么优先权为1
				else
					prec2 = 2;//如果栈顶元素为操作符'*'或者'/',那么优先权为2
				if (prec2 < prec1){//由于opThis的优先权大于opTop,所以opTop不需要弹出栈,因此需要重新把出栈的opTop重新压入栈顶
					stack.push(opTop+"");//重新把出栈的opTop重新压入栈顶并且跳出循环,然后会把opThis压入栈顶
					break;
				}else{
					output += opTop;//将操作符添加到输入字符串output中
				}
			}
		}//end while
		stack.push(opThis+"");//将opThis压入栈顶
	}
	/**
	 * 当输入字符opThis是右括号')'时,如果栈顶元素opTop不是左括号'(',就将栈顶元素opTop添加到字符串output中
	 * @param opThis
	 */
	public void getParen(char opThis){
		while (!stack.isEmpty()){
			char opTop = stack.pop().charAt(0);//弹出栈顶元素opTop
			if (opThis == ')' && opTop == '(')//如果栈顶元素opTop是左括号'(',就退出循环
				break;
			else
				output += opTop;//栈顶元素opTop不是左括号'(',将栈顶元素opTop添加到字符串output中
		}
	}
}

4、中缀表达式转后缀表达式测试
``
`package stack;

import java.io.IOException;

public class InfixApp {
public static void main(String[] args) throws IOException {
String input, output;
while(true){
System.out.print(“输入中缀表达式:”);
System.out.flush();
input = Util.getString();
if (input.equals(""))
break;
InToPost trans = new InToPost(input);
output = trans.doTrans();
System.out.println("后缀表达式: " + output);
}
}

}

java 解析运算规则_java_02

5、计算后缀表达式的值。这个比较容易理解,看代码注释就可以。

package stack;
/**
 * 						后缀表达式求值
 * |----------------------------------------------------------|
 * |从后缀表达式中读取的元素  |          执行的动作                                                                 |
 * |-----------------|----------------------------------------|
 * |     操作数                      |           入栈                                                                          |
 * |     操作符                      |从栈中提取两个操作数,用操作符将其执行运算。结果入栈             |
 * |----------------------------------------------------------|
 */
public class ParsePost {
	private StackE<Integer> stack;
	private String input;
	
	public ParsePost(String s){
		input = s;
	}
	/**
	 * 求解后缀表达式求值,目前只能求解个位数的值
	 * @return 返回计算结果
	 */
	public Integer doParse(){
		stack = new StackE<Integer>(20);//初始化一个大小为20的栈
		char ch;
		Integer num1, num2, tmpSum;
		for (int i = 0; i < input.length(); i++) {
			ch = input.charAt(i);//从后缀表达式中获取一个字符
			stack.displayStack("" + ch + " ");//打印当前的字符
			if (ch > '0' && ch <= '9'){
				stack.push(Integer.parseInt(ch+""));//如果是数字就入栈
			}else{//如果是操作符,就从栈顶开始,连续获取两个栈元素
				num2 = stack.pop();//获取第一个栈元素
				num1 = stack.pop();//获取第二个栈元素
				switch (ch) {
				case '+'://操作符ch为加,操作数num1和num2进行加法运行,运算结果保存到tmpSum中
					tmpSum = num1 + num2;
					break;
				case '-':
					tmpSum = num1 - num2;
					break;
				case '*':
					tmpSum = num1 * num2;
					break;
				case '/':
					tmpSum = num1 / num2;
					break;
				default:
					tmpSum = 0;
					break;
				}//end switch
				stack.push(tmpSum);//将结算结果tmpSum入栈
			}//end else
		}//end for
		tmpSum = stack.pop();//后缀表达式中的元素读取完后,将计算结果出栈
		return tmpSum;
	}
	
}
`

6、计算后缀表达式的值的测试代码及运行结果
package stack;

import java.io.IOException;
public class PostFixApp {
public static void main(String[] args) throws IOException {
String input;
Integer output;
while (true){
System.out.print(“输入后缀表达式: “);
System.out.flush();
input = Util.getString();//从键盘输入
if (input.equals(””))
break;
ParsePost parsePost = new ParsePost(input);
output = parsePost.doParse();//后缀表达式求值
System.out.println("解析后缀表达式后的值: " + output);
}
}

}

java 解析运算规则_java_03


7、将中缀表达式转后缀表达式跟解析后缀表达式的值一起测试,即解析算术表达式的完整测试

package stack;

import java.io.IOException;

public class InfixToPostFixApp {
public static void main(String[] args) throws IOException {

String infixInput, infixOutput;
	Integer postfixOutput;//保存解析的后缀表达式的值
	while(true){
		System.out.print("输入中缀表达式:");
		System.out.flush();
		infixInput = Util.getString();
		if (infixInput.equals(""))
			break;
		InToPost trans = new InToPost(infixInput);//中缀表达式转换成后缀表达式
		infixOutput = trans.doTrans();
		System.out.println("后缀表达式: " + infixOutput);
		
		ParsePost parsePost = new ParsePost(infixOutput);
		postfixOutput = parsePost.doParse();//后缀表达式求值
		System.out.println("解析后缀表达式的值: " + postfixOutput);
	}
}

}

java 解析运算规则_java 解析运算规则_04

java 解析运算规则_java 解析运算规则_05


8、其他代码

package stack;
 /**
• 通过Object的数组实现自定义的栈
• 
*/
 public class StackE {
 private int maxSize;//size of stack array
 private Object[] stackArray;
 private int top; //top of stack
//初始化栈,s是栈的大小
public StackE(int s){
	maxSize = s;//set array size
	stackArray = new Object[maxSize]; //create array
	top = -1;// no items yet
}

//将item压入栈顶
public void push(E item) {// put item on top of stack
	stackArray[++top] = item; //increment top, insert item
}

//将栈顶元素弹出并删除栈顶元素
public E pop() {//take item from top of stack
	return (E) stackArray[top--];//access item, decrement top
}
//将栈顶元素弹出,不会删除栈顶元素
public E peek(){//peek at top of stack
	return (E) stackArray[top];
}

//判断栈是否为空
public boolean isEmpty(){//true if stack is empty
	return top == -1;
}

//判断栈是否满了
public boolean isFull(){//true if stack is full
	return top == maxSize - 1;
}
//返回栈顶位置
public int getTop(){
	return top;
}

//将栈中的第n个元素弹出,不会删除该元素
public E peekN(int n){//peek at top of stack
	return (E) stackArray[n];
}

//获取栈的元素个数
public int size(){
	return top+1;
}

public void displayStack(String s){
	System.out.print(s);
	System.out.print("Stack (bottom-->top): ");
	for (int i = 0; i < size(); i++) {
		System.out.print(peekN(i));
		System.out.print(' ');
	}
	System.out.println();
}

}

package stack;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Util {
public static String getString() throws IOException{
InputStreamReader isr = new InputStreamReader(System.in);//从键盘输入
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
}

代码参考:https://github.com/gunder1129/android-tool/tree/master/JAVA%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%8F%8A%E7%AE%97%E6%B3%95

# 欢迎使用Markdown编辑器

你好! 这是你第一次使用 **Markdown编辑器** 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

## 新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
 1. **全新的界面设计** ,将会带来全新的写作体验;
 2. 在创作中心设置你喜爱的代码高亮样式,Markdown **将代码片显示选择的高亮样式** 进行展示;
 3. 增加了 **图片拖拽** 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
 4. 全新的 **KaTeX数学公式** 语法;
 5. 增加了支持**甘特图的mermaid语法[^1]** 功能;
 6. 增加了 **多屏幕编辑** Markdown文章功能;
 7. 增加了 **焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置** 等功能,功能按钮位于编辑区域与预览区域中间;
 8. 增加了 **检查列表** 功能。
 [^1]: [mermaid语法说明](https://mermaidjs.github.io/)

## 功能快捷键

撤销:<kbd>Ctrl/Command</kbd> + <kbd>Z</kbd>
重做:<kbd>Ctrl/Command</kbd> + <kbd>Y</kbd>
加粗:<kbd>Ctrl/Command</kbd> + <kbd>B</kbd>
斜体:<kbd>Ctrl/Command</kbd> + <kbd>I</kbd>
标题:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>H</kbd>
无序列表:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>U</kbd>
有序列表:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>O</kbd>
检查列表:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>C</kbd>
插入代码:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>K</kbd>
插入链接:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>L</kbd>
插入图片:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>G</kbd>
查找:<kbd>Ctrl/Command</kbd> + <kbd>F</kbd>
替换:<kbd>Ctrl/Command</kbd> + <kbd>G</kbd>

## 合理的创建标题,有助于目录的生成

直接输入1次<kbd>#</kbd>,并按下<kbd>space</kbd>后,将生成1级标题。
输入2次<kbd>#</kbd>,并按下<kbd>space</kbd>后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用`TOC`语法后生成一个完美的目录。

## 如何改变文本的样式

*强调文本* _强调文本_

**加粗文本** __加粗文本__

==标记文本==

~~删除文本~~

> 引用文本

H~2~O is是液体。

2^10^ 运算结果是 1024.

## 插入链接与图片

链接: [link]().

图片: ![Alt]()

带尺寸的图片: ![Alt]( =30x30)

居中的图片: ![Alt](#pic_center)

居中并且带尺寸的图片: ![Alt](#pic_center =30x30)

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

## 如何插入一段漂亮的代码片

去[博客设置]()页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 `代码片`.
```javascript
// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
  • 项目
  • 项目
  1. 项目1
  2. 项目2
  3. 项目3


创建一个表格

一个简单的表格是这么创建的:

项目

Value

电脑

$1600

手机

$12

导管

$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列

第二列

第三列

第一列文本居中

第二列文本居右

第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPE

ASCII

HTML

Single backticks

'Isn't this fun?'

‘Isn’t this fun?’

Quotes

"Isn't this fun?"

“Isn’t this fun?”

Dashes

-- is en-dash, --- is em-dash

– is en-dash, — is em-dash

创建一个自定义列表

HTML

Authors John Luke

如何创建一个注脚

一个具有注脚的文本。1

注释也是必不可少的

Markdown将文本转换为 HTML。

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 java 解析运算规则_java 解析运算规则_06

java 解析运算规则_java_07

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章


Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid


  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:


张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五


这将产生一个流程图。:


链接




长方形

圆角长方形

菱形


  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:


Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no


  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. 注脚的解释 ↩︎