1.概念
你可能聽說過表達式,a+b,a+b*c這些,但是前綴表達式,前綴記法,中綴表達式,波蘭式,后綴表達式,后綴記法,逆波蘭式這些都是也是表達式。
a+b,a+b*c這些看上去比較正常的是中綴表達式,就是運算符放在兩個操作數之間。前綴表達式是將運算符放在相關操作數之前,后綴表達式是將運算符放在操作數之后。
至於前面說的那些概念:
前綴表達式就是波蘭式就是前綴記法
后綴表達式就是逆波蘭式就是后綴記法
舉例如下:
(3+4)*5-6就是中綴表達式
-*+3456就是前綴表達式
34+5*6-就是后綴表達式
雖然人的大腦很容易理解與分析中綴表達式,但是對於計算機來說中綴表達式確是很復雜的,因此計算表達式的值時通常需要把中置表達式轉換為前置或者后置表達式,然后再進行求值。對於計算機來說,計算前綴表達式或者后置表達式非常簡單。
2.中置表達式轉換為后置表達式
中綴表達式a + b * c + ( d * e + f ) * g,轉化為后綴表達式之后是a b c * + d e * f + g * +,具體的轉換過程如下:
1)如果遇到操作數,直接將其輸出
2)如果遇到操作符,則將其放入棧中,遇到左括號也將其放入棧中
3)如果遇到一個右括號,則將棧元素彈出,將彈出的操作符輸出直到遇到左括號為止,左括號只彈出不輸出
4)遇到其他的操作符例如 + ,* , (從棧中彈出元素直到遇到發現更低優先級的元素或者棧空為止。彈出這些元素之后,才能將遇到的操作符壓入到棧中,有一點要注意,只有遇到 ) 的情況下才彈出 ( 其他情況下都不會彈出 (
5)如果讀到了輸入的末尾,則將棧中的所有元素依次彈出
3.示例
規則很多,還是用實例比較容易說清楚整個過程。以上面的轉換為例,輸入為a + b * c + (d * e + f)*g,處理過程如下:
1)首先讀到a,直接輸出。
2)讀到“+”,將其放入到棧中。
3)讀到b,直接輸出。
表達式 * c + (d * e + f) * g, 此時棧和輸出的情況如下:
4)讀到“*”,因為棧頂元素"+"優先級比" * " 低,所以將" * "直接壓入棧中。
5)讀到c,直接輸出。
表達式 + (d * e + f) * g, 此時棧和輸出情況如下:
6)讀到" + ",因為棧頂元素" * "的優先級比它高,所以彈出" * "並輸出, 同理,棧中下一個元素" + "優先級與讀到的操作符" + "一樣,所以也要彈出並輸出。然后再將讀到的" + "壓入棧中。
表達式 (d * e + f) * g,此時棧和輸出情況如下:
7)下一個讀到的為"(",它優先級最高,所以直接放入到棧中。
8)讀到d,將其直接輸出。
表達式 * e + f) * g,此時棧和輸出情況如下:
9)讀到" * ",由於只有遇到" ) "的時候左括號"("才會彈出,所以" * "直接壓入棧中。
10)讀到e,直接輸出。
表達式 + f) * g,此時棧和輸出情況如下:
11)讀到" + ",彈出" * "並輸出,然后將"+"壓入棧中。
12)讀到f,直接輸出。
表達式 ) * g,此時棧和輸出情況:
13)接下來讀到“)”,則直接將棧中元素彈出並輸出直到遇到"("為止。這里右括號前只有一個操作符"+"被彈出並輸出。
表達式 * g
14)讀到" * ",壓入棧中。讀到g,直接輸出。
表達式為空
15)此時輸入數據已經讀到末尾,棧中還有兩個操作符“*”和" + ",直接彈出並輸出。表達式 a + b * c + (d * e + f) * g
至此整個轉換過程完成。程序實現代碼后續再補充了
4.后綴表達式求值
假設一個后綴表達式為 6 5 2 3 + 8 * + 3 + * ,則其求值過程如下:
1)遍歷表達式,遇到的數字首先放入棧中,此時棧如下所示:
2)接着讀到“+”,則彈出3和2,執行3+2,計算結果等於5,並將5壓入到棧中。
3)讀到8,將其直接放入棧中。
4)讀到“*”,彈出8和5,執行8*5,並將結果40壓入棧中。而后過程類似,讀到“+”,將40和5彈出,將40+5的結果45壓入棧...以此類推。最后求的值288。
//使用數組dataStore保存站內元素,構造函數將其初始化為一個空數組。 //變量top定義棧頂的位置,構造時初始化為0,表示棧的起始位置為0 function Stack(){ this.dataStore = []; this.top = 0; this.push = push; this.pop = pop; this.peek = peek; this.clear = clear; this.length = length; this.printElement = printStack; //注意++操作符的位置,它放在this.top的后面,這樣新入棧的元素就被放在top的當前位置對應的位置,同時top自加1,指向下一個位置 function push(element){ this.dataStore[this.top++] = element; } //返回棧頂元素,同時top的位置減1 function pop(){ return this.dataStore[--this.top]; } //peek()方法返回數組的第top-1個位置的元素,即棧頂元素 function peek(){ return this.dataStore[this.top-1]; } //將top的值設置0,即清空一個棧 function clear(){ this.top = 0; } //返回變量top的值即為棧內元素的個數 function length(){ return this.top; } //輸出棧內元素 function printStack(){ while (this.top>0){ document.writeln(this.pop()+" "); } } } /*-------------------棧將中綴表達式轉換成后綴表達式-------------------*/ document.write('<br><br>'); function suffixExpression(){ var str = 'a+b*c+(d*e+f)*g'; var stack = new Stack(); var outStack = new Array(); for (var i=0; i<str.length; ++i) { if(')' == str[i]){ while (true){ var top = stack.peek(); stack.pop(); if('(' != top){ outStack[outStack.length] = top; }else{ break; } } }else if(['-','+'].indexOf(str[i])>-1){ if(['*','/'].indexOf(stack.peek())>-1){ while (['*','/'].indexOf(stack.peek())>-1){ outStack[outStack.length] = stack.peek(); stack.pop(); } outStack[outStack.length] = str[i]; }else{ stack.push(str[i]); } }else if(['(','*','/'].indexOf(str[i])>-1){ stack.push(str[i]); }else{ outStack[outStack.length] = str[i]; } } for (var i=0; i< outStack.length; i++) { document.write(outStack[i]); } } suffixExpression(); /*-------------------用棧結構求后綴表達式的值-------------------*/ document.write('<br><br>'); function countSuffixExpression(){ var str = '6523+8*+3+*'; var stack = new Stack(); for (var i=0; i<str.length; i++) { if(isNaN(str[i])){ stack.push( eval( stack.pop() + str[i] + stack.pop()) ); }else{ stack.push(str[i]) } } document.write(stack.pop()); } countSuffixExpression();
輸出結果如下: