帶你了解Java數(shù)據(jù)結(jié)構(gòu)和算法之前綴,中綴和后綴表達(dá)式
1、人如何解析算術(shù)表達(dá)式
如何解析算術(shù)表達(dá)式?或者換種說(shuō)法,遇到某個(gè)算術(shù)表達(dá)式,我們是如何計(jì)算的:
①、求值 3+4-5

這個(gè)表達(dá)式,我們?cè)诳吹?+4后都不能直接計(jì)算3+4的值,知道看到4后面的 - 號(hào),因?yàn)闇p號(hào)的優(yōu)先級(jí)和前面的加號(hào)一樣,所以可以計(jì)算3+4的值了,如果4后面是 * 或者 /,那么就要在乘除過(guò)后才能做加法操作,比如:
②、求值 3+4*5

這個(gè)不能先求3+4的值,因?yàn)?后面的*運(yùn)算級(jí)別比前面的+高。通過(guò)這兩個(gè)表達(dá)式的說(shuō)明,我們可以總結(jié)解析表達(dá)式的時(shí)候遵循的幾條規(guī)則:
- ①、從左到右讀取算式。
- ②、已經(jīng)讀到了可以計(jì)算值的兩個(gè)操作數(shù)和一個(gè)操作符時(shí),可以計(jì)算,并用計(jì)算結(jié)果代替那兩個(gè)操作數(shù)和一個(gè)操作符。
- ③、繼續(xù)這個(gè)過(guò)程,從左到右,能算就算,直到表達(dá)式的結(jié)尾。
2、計(jì)算機(jī)如何解析算術(shù)表達(dá)式
對(duì)于前面的表達(dá)式 3+4-5,我們?nèi)耸怯兴季S能力的,能根據(jù)操作符的位置,以及操作符的優(yōu)先級(jí)別能算出該表達(dá)式的結(jié)果。但是計(jì)算機(jī)怎么算?
計(jì)算機(jī)必須要向前(從左到右)來(lái)讀取操作數(shù)和操作符,等到讀取足夠的信息來(lái)執(zhí)行一個(gè)運(yùn)算時(shí),找到兩個(gè)操作數(shù)和一個(gè)操作符進(jìn)行運(yùn)算,有時(shí)候如果后面是更高級(jí)別的操作符或者括號(hào)時(shí),就必須推遲運(yùn)算,必須要解析到后面級(jí)別高的運(yùn)算,然后回頭來(lái)執(zhí)行前面的運(yùn)算。我們發(fā)現(xiàn)這個(gè)過(guò)程是極其繁瑣的,而計(jì)算機(jī)是一個(gè)機(jī)器,只認(rèn)識(shí)高低電平,想要完成一個(gè)簡(jiǎn)單表達(dá)式的計(jì)算,我們可能要設(shè)計(jì)出很復(fù)雜的邏輯電路來(lái)控制計(jì)算過(guò)程,那更不用說(shuō)很復(fù)雜的算術(shù)表達(dá)式,所以這樣來(lái)解析算術(shù)表達(dá)式是不合理的,那么我們應(yīng)該采取什么辦法呢?
請(qǐng)大家先看看什么是前綴表達(dá)式,中綴表達(dá)式,后綴表達(dá)式:這三種表達(dá)式其實(shí)就是算術(shù)表達(dá)式的三種寫法,以 3+4-5為例
- ①、前綴表達(dá)式:操作符在操作數(shù)的前面,比如 +-543
- ②、中綴表達(dá)式:操作符在操作數(shù)的中間,這也是人類最容易識(shí)別的算術(shù)表達(dá)式 3+4-5
- ③、后綴表達(dá)式:操作符在操作數(shù)的后面,比如 34+5-
上面我們講的人是如何解析算術(shù)表達(dá)式的,也就是解析中綴表達(dá)式,這是人最容易識(shí)別的,但是計(jì)算機(jī)不容易識(shí)別,計(jì)算機(jī)容易識(shí)別的是前綴表達(dá)式和后綴表達(dá)式,將中綴表達(dá)式轉(zhuǎn)換為前綴表達(dá)式或者后綴表達(dá)式之后,計(jì)算機(jī)能很快計(jì)算出表達(dá)式的值,那么中綴表達(dá)式是如何轉(zhuǎn)換為前綴表達(dá)式和后綴表達(dá)式,以及計(jì)算機(jī)是如何解析前綴表達(dá)式和后綴表達(dá)式來(lái)得到結(jié)果的呢?
3、后綴表達(dá)式
后綴表達(dá)式,指的是不包含括號(hào),運(yùn)算符放在兩個(gè)運(yùn)算對(duì)象的后面,所有的計(jì)算按運(yùn)算符出現(xiàn)的順序,嚴(yán)格從左向右進(jìn)行(不再考慮運(yùn)算符的優(yōu)先規(guī)則)。
由于后綴表達(dá)式的運(yùn)算符在兩個(gè)操作數(shù)的后面,那么計(jì)算機(jī)在解析后綴表達(dá)式的時(shí)候,只需要從左向右掃描,也就是只需要向前掃描,而不用回頭掃描,遇到運(yùn)算符就將運(yùn)算符放在前面兩個(gè)操作符的中間(這里先不考慮乘方類似的單目運(yùn)算),一直運(yùn)算到最右邊的運(yùn)算符,那么就得出運(yùn)算結(jié)果了。既然后綴表達(dá)式這么好,那么問(wèn)題來(lái)了:
①、如何將中綴表達(dá)式轉(zhuǎn)換為后綴表達(dá)式?
對(duì)于這個(gè)問(wèn)題,轉(zhuǎn)換的規(guī)則如下:

一、先自定義一個(gè)棧
package com.ys.poland;
public class MyCharStack {
private char[] array;
private int maxSize;
private int top;
public MyCharStack(int size){
this.maxSize = size;
array = new char[size];
top = -1;
}
//壓入數(shù)據(jù)
public void push(char value){
if(top < maxSize-1){
array[++top] = value;
}
}
//彈出棧頂數(shù)據(jù)
public char pop(){
return array[top--];
}
//訪問(wèn)棧頂數(shù)據(jù)
public char peek(){
return array[top];
}
//查看指定位置的元素
public char peekN(int n){
return array[n];
}
//為了便于后面分解展示棧中的內(nèi)容,我們?cè)黾恿艘粋€(gè)遍歷棧的方法(實(shí)際上棧只能訪問(wèn)棧頂元素的)
public void displayStack(){
System.out.print("Stack(bottom-->top):");
for(int i = 0 ; i < top+1; i++){
System.out.print(peekN(i));
System.out.print(' ');
}
System.out.println("");
}
//判斷棧是否為空
public boolean isEmpty(){
return (top == -1);
}
//判斷棧是否滿了
public boolean isFull(){
return (top == maxSize-1);
}
}二、前綴表達(dá)式轉(zhuǎn)換為后綴表達(dá)式
package com.ys.poland;
public class InfixToSuffix {
private MyCharStack s1;//定義運(yùn)算符棧
private MyCharStack s2;//定義存儲(chǔ)結(jié)果棧
private String input;
//默認(rèn)構(gòu)造方法,參數(shù)為輸入的中綴表達(dá)式
public InfixToSuffix(String in){
input = in;
s1 = new MyCharStack(input.length());
s2 = new MyCharStack(input.length());
}
//中綴表達(dá)式轉(zhuǎn)換為后綴表達(dá)式,將結(jié)果存儲(chǔ)在棧中返回,逆序顯示即后綴表達(dá)式
public MyCharStack doTrans(){
for(int j = 0 ; j < input.length() ; j++){
System.out.print("s1棧元素為:");
s1.displayStack();
System.out.print("s2棧元素為:");
s2.displayStack();
char ch = input.charAt(j);
System.out.println("當(dāng)前解析的字符:"+ch);
switch (ch) {
case '+':
case '-':
gotOper(ch,1);
break;
case '*':
case '/':
gotOper(ch,2);
break;
case '(':
s1.push(ch);//如果當(dāng)前字符是'(',則將其入棧
break;
case ')':
gotParen(ch);
break;
default:
//1、如果當(dāng)前解析的字符是操作數(shù),則直接壓入s2
//2、
s2.push(ch);
break;
}//end switch
}//end for
while(!s1.isEmpty()){
s2.push(s1.pop());
}
return s2;
}
public void gotOper(char opThis,int prec1){
while(!s1.isEmpty()){
char opTop = s1.pop();
if(opTop == '('){//如果棧頂是'(',直接將操作符壓入s1
s1.push(opTop);
break;
}else{
int prec2;
if(opTop == '+' || opTop == '-'){
prec2 = 1;
}else{
prec2 = 2;
}
if(prec2 < prec1){//如果當(dāng)前運(yùn)算符比s1棧頂運(yùn)算符優(yōu)先級(jí)高,則將運(yùn)算符壓入s1
s1.push(opTop);
break;
}else{//如果當(dāng)前運(yùn)算符與棧頂運(yùn)算符相同或者小于優(yōu)先級(jí)別,那么將S1棧頂?shù)倪\(yùn)算符彈出并壓入到S2中
//并且要再次再次轉(zhuǎn)到while循環(huán)中與 s1 中新的棧頂運(yùn)算符相比較;
s2.push(opTop);
}
}
}//end while
//如果s1為空,則直接將當(dāng)前解析的運(yùn)算符壓入s1
s1.push(opThis);
}
//當(dāng)前字符是 ')' 時(shí),如果棧頂是'(',則將這一對(duì)括號(hào)丟棄,否則依次彈出s1棧頂?shù)淖址?,壓入s2,直到遇到'('
public void gotParen(char ch){
while(!s1.isEmpty()){
char chx = s1.pop();
if(chx == '('){
break;
}else{
s2.push(chx);
}
}
}
}三、測(cè)試
@Test
public void testInfixToSuffix(){
String input;
System.out.println("Enter infix:");
Scanner scanner = new Scanner(System.in);
input = scanner.nextLine();
InfixToSuffix in = new InfixToSuffix(input);
MyCharStack my = in.doTrans();
my.displayStack();
}四、結(jié)果

五、分析

②、計(jì)算機(jī)如何實(shí)現(xiàn)后綴表達(dá)式的運(yùn)算?

4、前綴表達(dá)式
前綴表達(dá)式,指的是不包含括號(hào),運(yùn)算符放在兩個(gè)運(yùn)算對(duì)象的前面,嚴(yán)格從右向左進(jìn)行(不再考慮運(yùn)算符的優(yōu)先規(guī)則),所有的計(jì)算按運(yùn)算符出現(xiàn)的順序。
注意:后綴表達(dá)式是從左向右解析,而前綴表達(dá)式是從右向左解析。
①、如何將中綴表達(dá)式轉(zhuǎn)換為前綴表達(dá)式?

②、計(jì)算機(jī)如何實(shí)現(xiàn)前綴表達(dá)式的運(yùn)算?

總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java系統(tǒng)運(yùn)行緩慢等問(wèn)題的排查思路
這篇文章主要介紹了Java系統(tǒng)運(yùn)行緩慢等問(wèn)題的排查思路,讀者可以根據(jù)具體情況具體分析,從而解決問(wèn)題2021-04-04
Java?Hibernate中一對(duì)多和多對(duì)多關(guān)系的映射方式
Hibernate是一種Java對(duì)象關(guān)系映射框架,支持一對(duì)多和多對(duì)多關(guān)系的映射。一對(duì)多關(guān)系可以使用集合屬性和單向/雙向關(guān)聯(lián)來(lái)映射,多對(duì)多關(guān)系可以使用集合屬性和中間表來(lái)映射。在映射過(guò)程中,需要注意級(jí)聯(lián)操作、延遲加載、中間表的處理等問(wèn)題2023-04-04
SpringBoot配置文件bootstrap和application區(qū)別及說(shuō)明
這篇文章主要介紹了SpringBoot配置文件bootstrap和application區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
Java生產(chǎn)1-100的隨機(jī)數(shù)簡(jiǎn)單實(shí)例(分享)
下面小編就為大家?guī)?lái)一篇Java生產(chǎn)1-100的隨機(jī)數(shù)簡(jiǎn)單實(shí)例(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
Springboot+Spring Security實(shí)現(xiàn)前后端分離登錄認(rèn)證及權(quán)限控制的示例代碼
本文主要介紹了Springboot+Spring Security實(shí)現(xiàn)前后端分離登錄認(rèn)證及權(quán)限控制的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
spring?項(xiàng)目實(shí)現(xiàn)限流方法示例
這篇文章主要為大家介紹了spring項(xiàng)目實(shí)現(xiàn)限流的方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
基于maven搭建一個(gè)ssm的web項(xiàng)目的詳細(xì)圖文教程
這篇文章主要介紹了基于maven搭建一個(gè)ssm的web項(xiàng)目的詳細(xì)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
JVM內(nèi)存管理之JAVA語(yǔ)言的內(nèi)存管理詳解
下面小編就為大家?guī)?lái)一篇JVM內(nèi)存管理之JAVA語(yǔ)言的內(nèi)存管理詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08

