字符串表達式的計算
步驟:
(1) 初始化兩個棧:運算符棧S1和儲存中間結果的棧S2;
(2) 從左至右掃描中綴表達式;
(3) 遇到操作數時,將其壓入S2;
(4) 遇到運算符時,比較其與S1棧頂運算符的優先級:
(4-1) 如果S1為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
(4-2) 比棧頂高,也將運算符壓入S1 (注意轉換為前綴表達式時是優先級較高或相同,而這里則不包括相同的情況);
(4-3) 比棧頂低或相同,將S1棧頂的運算符彈出並壓入到S2中,再次轉到(4-1)與S1中新的棧頂運算符相比較;
(5) 遇到括號時:
(5-1) 如果是左括號“(”,則直接壓入S1;
(5-2) 如果是右括號“)”,則依次彈出S1棧頂的運算符,並壓入S2,直到遇到左括號為止,此時將這一對括號丟棄;
(6) 重復步驟(2)至(5),直到表達式的最右邊;
(7) 將S1中剩余的運算符依次彈出並壓入S2;
(8) 依次彈出S2中的元素並輸出,結果的逆序即為中綴表達式對應的后綴表達式(轉換為前綴表達式時不用逆序)。
例:1+((2+3)×4)-5

java版 | 詳見
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
sc.close();
System.out.println(getResult(getPost(s)));
}
/**
* 計算后綴表達式的值
* @param list 后綴表達式
* @return
*/
public static int getResult(List<Character> list) {
Stack<String> stack = new Stack<>();
for(int i = 0; i < list.size(); i++) {
char c = list.get(i);
if(c >= '0' && c <= '9') { //當遇到操作數直接壓棧
stack.push(c + "");
}
else {//當遇到操作符的時候,從棧中彈出兩個元素,然后根據運算符的不同做相應的運算,然后把運算結果壓棧。
int b = Integer.parseInt(stack.pop());
int a = Integer.parseInt(stack.pop());
if(c == '+') stack.push(a + b + "");
else if(c == '-') stack.push(a - b + "");
else if(c == '*') stack.push(a * b + "");
else stack.push(a / b + "");
}
}
//最終棧中肯定只剩下一個元素,就是計算的結果。
return Integer.parseInt(stack.pop());
}
/**
* 把中綴表達式轉為后綴表達式
* 前提條件:操作數的范圍為0-9,操作符為+,-,*,/,以及()
* @param s 字符串表達式
* @return
*/
public static List<Character> getPost(String s) {
Stack<Character> stack = new Stack<>(); //保存操作符
LinkedList<Character> list = new LinkedList<>(); //保存最終的后綴表達式
for(int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(c >= '0' && c <= '9') list.add(c); //操作數直接輸出到后綴表達式中
else if(c == '+' || c == '-' || c == '*' || c == '/') {
//把比當前操作符c的優先級高或者等於c的優先級的操作符依次彈出棧並保存到后綴表達式中,直到遇到棧頂操作符的優先級比c低
while(!stack.isEmpty()) {
if(compare(stack.peek()) >= compare(c)) {
list.add(stack.pop());
}
else break;
}
stack.push(c);//當前操作符c入棧
}
else if(c == '(') stack.push(c); //左括號直接入棧
else {
//當遇到右括號的時候,把棧中的操作符依次彈出並追加到后綴表達式中,直到遇到左括號停止,並把左括號彈出。
while(stack.peek() != '(') {
list.add(stack.pop());
}
stack.pop();
}
}
//把棧中所有的操作符全部彈出追加到后綴表達式中
while(!stack.isEmpty())list.add(stack.pop());
return list;
}
/**
* 計算運算符的優先級
* @param c 運算符
* @return
*/
public static int compare(char c) {
if(c == '+' || c == '-') return 1;
else if(c == '*' || c == '/') return 2;
else return 0;
}
}
c++版
#define STACK_MAX 64
#define BOTTOM_NUMBER -1
typedef struct{
int TOP;
const int BOTTOM;
char STACK_M[STACK_MAX];
}STACK_BASE_TY;
我們采用數組STACK_M 作為棧的實體,BOTTOM作為棧底,
使用數組作為棧的實體,那么就可以規定棧底的索引值為“-1”。
棧從0~STACK_MAX-1正向增長。
當然我們還要編寫棧的操作方法,為了方便管理我們編寫一個結構體來管理函數。
typedef struct {
void (*Initial) ( STACK_BASE_TY *pStack);
int (*Push) ( STACK_BASE_TY *pStack, int data);
int (*Pop) ( STACK_BASE_TY *pStack, char *pdata);
char (*GetTopData) ( STACK_BASE_TY *pStack);
int (*GetTopLocate) ( STACK_BASE_TY *pStack);
}STACK_OPTION_TY;
我們規划一下每個函數的功能:
1.初始化棧,初始化棧的目的是建立一個空棧。即將TOP指針指向BOTTOM。pStack指向要初始化的棧的實體。
2.壓棧,將一個數據的值壓入棧頂。返回0,棧滿,壓入錯誤;返回1,壓棧成功。
3.出棧,彈出棧頂的數據。*pdata接收出棧數據的值。返回0,棧空,出棧錯誤;返回1,出棧成功。
4.獲取棧頂數據值,但是棧頂指針不發生變化。
5.獲取棧頂的位置。
void initialStack( STACK_BASE_TY *pStack )
{
int i;
pStack->TOP = -1;
for( i =0; i< STACK_MAX; i++ ) pStack->STACK_M[i]=0;
}
int pushStack( STACK_BASE_TY *pStack, int data )
{
pStack->TOP++;
if( pStack->TOP>=STACK_MAX )
{
pStack->TOP--;
return 0;
}
else
{
pStack->STACK_M[ pStack->TOP] = data;
return 1;
}
}
int popStack( STACK_BASE_TY *pStack, char *pdata )
{
if(pStack->TOP<=pStack->BOTTOM)
{
return 0;
}
else
{
*pdata = pStack->STACK_M[pStack->TOP];
pStack->TOP--;
return 1;
}
}
int getStackTopLocate(STACK_BASE_TY *pStack)
{
return pStack->TOP;
}
char getTopData( STACK_BASE_TY *pStack )
{
return pStack->STACK_M[pStack->TOP];
}
定義兩個棧,
STACK_BASE_TY statck_option={0,-1,{0,0}};
STACK_BASE_TY statck_result={0,-1,{0,0}};
STACK_BASE_TY* const pOptionStatck = &statck_option;
STACK_BASE_TY* const pResultStatck = &statck_result;
statck_option存放運算符號,statck_result存放最終結果。
STACK_OPTION_TY stackOption = {initialStack,pushStack,popStack,getTopData,getStackTopLocate} ;
定義一個函數結構體,並且初始化,使得我們可以方便的調用棧的操作方法。
const char str[] = "(1+2+3)*(4+5)"; 測試公式
int main( )
{
unsigned int i;
char temp;
char opCh_0,opCh_1;
int compPr;
stackOption.Initial(pOptionStatck);
stackOption.Initial(pResultStatck);
for( i=0; i<strlen(str); i++)
{
switch( str[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
stackOption.Push(pResultStatck,str[i]);
break;
case '+':
case '-':
if( stackOption.GetTopLocate(pOptionStatck) ==-1 )
{
stackOption.Push(pOptionStatck,str[i]);
}
else
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if( opCh_0=='(')
{
stackOption.Push(pOptionStatck,str[i]);
}
else
{
while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&&
(opCh_0!='('))
{
if(stackOption.Pop(pOptionStatck,&opCh_0 )!=0)
{
if(opCh_0!='(')
{
stackOption.Push(pResultStatck, opCh_0);
}
}
}
stackOption.Push(pOptionStatck,str[i] );
}
}
break;
case '*':
case '/':
if( stackOption.GetTopLocate(pOptionStatck) ==-1 )
{
stackOption.Push(pOptionStatck,str[i]);
}
else
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if(( opCh_0=='(')||(opCh_0=='+')||(opCh_0=='-'))
{
stackOption.Push(pOptionStatck,str[i]);
}
else
{
while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&&
(opCh_0!='('))
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if(( opCh_0=='(')||(opCh_0=='+')||(opCh_0=='-'))
{
break;
}
else
{
stackOption.Pop(pOptionStatck,&opCh_0);
stackOption.Push(pResultStatck,opCh_0);
}
}
stackOption.Push(pOptionStatck,str[i] );
}
}
break;
case '(':
stackOption.Push(pOptionStatck,str[i]);
break;
case ')':
if( stackOption.GetTopLocate(pOptionStatck) ==-1 )
{
}
else
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if( opCh_0=='(')
{
stackOption.Pop(pOptionStatck,&opCh_0);
}
else
{
while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&&
(opCh_0!='('))
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if( opCh_0!='(')
{
stackOption.Pop(pOptionStatck,&opCh_0);
stackOption.Push(pResultStatck,opCh_0);
}
else
{
stackOption.Pop(pOptionStatck,&opCh_0);
}
}
}
}
break;
default:
break;
}
}
while(stackOption.Pop(pOptionStatck,&opCh_0)!=0)
{
stackOption.Push(pResultStatck,opCh_0);
}
while(stackOption.Pop(pResultStatck,&opCh_0)!=0)
{
printf("%c,",opCh_0);
}
printf("\n");
return 0;
}
