我們在數學中常見的計算式,例如2+(3*4)叫做中綴表達式。表達式中涉及到了多個運算符,而運算符之間是有優先級的。計算機在計算並且處理這種表達式時,需要將中綴表達式轉換成後綴表達式,然後再進行計算。
中綴表達式:0.3/(5*2+1) 的等價後綴表達式是:0.3 5 2 * 1 + /
中綴表達式轉後綴表達式遵循以下原則:
1.遇到操作數,直接輸出;
2.棧爲空時,遇到運算符,入棧;
3.遇到左括號,將其入棧;
4.遇到右括號,執行出棧操作,並將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出;
5.遇到其他運算符'+''-''*''/'時,彈出所有優先級大於或等於該運算符的棧頂元素,然後將該運算符入棧;
6.最終將棧中的元素依次出棧,輸出。
經過上面的步驟,得到的輸出既是轉換得到的後綴表達式。
舉例:a+b*c+(d*e+f)*g ---------> abc*+de*f+g*+
遇到a,直接輸出:
遇到+,此時棧爲空,入棧:
遇到b,直接輸出:
遇到*,優先級大於棧頂符號優先級,入棧:
遇到c,輸出:
遇到+,目前站內的*與+優先級都大於或等於它,因此將棧內的*,+依次彈出並且輸出,並且將遇到的這個+入棧:
遇到(,將其入棧:
遇到d,直接輸出:
遇到*,由於*的優先級高於處在棧中的(,因此*入棧:
遇到e,直接輸出:
遇到+,棧頂的*優先級高於+,但是棧內的(低於+,將*出棧輸出,+入棧:
遇到f,直接輸出:
遇到),彈出棧頂元素並且輸出,直到彈出(才結束,在這裏也就是彈出+輸出,彈出(不輸出:
遇到*,優先級高於棧頂+,將*入棧:
遇到g,直接輸出:
此時已經沒有新的字符了,依次出棧並輸出操作直到棧爲空:
明白了這個過程,現在就需要用代碼實現了。對於各種運算符的優先級,可以使用整數來表示運算符的級別。可以定義一個函數來返回各種符號的優先級數字。
//MyStack.h
#include <iostream>
using namespace std;
const static int MAXSIZE =100;
template <class ElemType> class MyStack
{
public:
ElemType data[MAXSIZE];
int top;
public:
void init(); // 初始化棧
bool empty(); // 判斷棧是否爲空
ElemType gettop(); // 讀取棧頂元素(不出棧)
void push(ElemType x); // 進棧
ElemType pop(); // 出棧
};
template<class T> void MyStack<T>::init()
{
this->top = 0;
}
template<class T> bool MyStack<T>::empty()
{
return this->top == 0? true : false;
}
template<class T> T MyStack<T>::gettop()
{
if(empty())
{
cout << "棧爲空!\n";
exit(1);
}
return this->data[this->top-1];
}
template<class T> void MyStack<T>::push(T x)
{
if(this->top == MAXSIZE)
{
cout << "棧已滿!\n";
exit(1);
}
this->data[this->top] =x;
this->top ++;
}
template<class T> T MyStack<T>::pop()
{
if(this->empty())
{
cout << "棧爲空! \n";
exit(1);
}
T e =this->data[this->top-1];
this->top --;
return e;
}
// PrefixToPostfix.h
#include <vector>
using namespace std;
bool isoperator(char op); // 判斷是否爲運算符
int priority(char op); // 求運算符優先級
void postfix(char pre[] , char post[],int &n); // 把中綴表達式轉換爲後綴表達式
double read_number(char str[],int *i); // 將數字字符串轉變成相應的數字
double postfix_value(char post[]); // 由後綴表達式字符串計算相應的中值表達式的值
// PrefixToPostfix.cpp
#include "MyStack.h"
#include "PrefixToPostfix.h"
#include <iostream>
using namespace std;
void main()
{
MyStack<int> stack ;
stack.init();
//char pre[] ="22/(5*2+1)#";
char exp[100];
cout << "輸入表達式(中綴,以#結束):";
cin >> exp;
char post[100] ;
//cout <<"中綴表達式爲:"<< pre << endl;
int n =0; // 返回後綴表達式的長度
postfix(exp,post,n);
cout <<"後綴表達式爲:";
for( int i =0 ;i < n ;i++)
cout << post[i] ;
cout << "\n由後綴表達式計算出的數值結果: ";
cout << postfix_value(post) << endl;
system("pause");
}
bool isoperator(char op)
{
switch(op)
{
case '+':
case '-':
case '*':
case '/':
return 1;
default :
return 0;
}
}
int priority(char op)
{
switch(op)
{
case '#':
return -1;
case '(':
return 0;
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default :
return -1;
}
}
// 把中綴表達式轉換爲後綴表達式,返回後綴表達式的長度(包括空格)
void postfix(char pre[] ,char post[],int &n)
{
int i = 0 ,j=0;
MyStack<char> stack;
stack.init(); // 初始化存儲操作符的棧
stack.push('#'); // 首先把結束標誌‘#’放入棧底
while(pre[i]!='#')
{
if((pre[i]>='0' && pre[i] <='9')||pre[i] =='.') // 遇到數字和小數點直接寫入後綴表達式
{
post[j++] = pre[i];
n++;
}
else if (pre[i]=='(') // 遇到“(”不用比較直接入棧
stack.push(pre[i]);
else if(pre[i] ==')') // 遇到右括號將其對應左括號後的操作符(操作符棧中的)全部寫入後綴表達式
{
while(stack.gettop()!='(')
{
post[j++] = stack.pop();
n++;
}
stack.pop(); // 將“(”出棧,後綴表達式中不含小括號
}
else if (isoperator(pre[i]))
{
post[j++] = ' '; // 用空格分開操作數(
n++;
while(priority(pre[i]) <= priority(stack.gettop()))
{
// 當前的操作符小於等於棧頂操作符的優先級時,將棧頂操作符寫入到後綴表達式,重複此過程
post[j++] = stack.pop();
n++;
}
stack.push(pre[i]); // 當前操作符優先級大於棧頂操作符的優先級,將該操作符入棧
}
i++;
}
while(stack.top) // 將所有的操作符加入後綴表達式
{
post[j++] = stack.pop();
n++;
}
}
double read_number(char str[],int *i)
{
double x=0.0;
int k = 0;
while(str[*i] >='0' && str[*i]<='9') // 處理整數部分
{
x = x*10+(str[*i]-'0');
(*i)++;
}
if(str[*i]=='.') // 處理小數部分
{
(*i)++;
while(str[*i] >= '0'&&str[*i] <='9')
{
x = x * 10 + (str[*i]-'0');
(*i)++;
k++;
}
}
while(k!=0)
{
x /= 10.0;
k--;
}
return x;
}
double postfix_value(char post[])
{
MyStack<double> stack; // 操作數棧
stack.init();
int i=0 ;
double x1,x2;
while(post[i] !='#')
{
if(post[i] >='0' && post[i] <='9')
stack.push(read_number(post,&i));
else if(post[i] == ' ')
i++;
else if (post[i] =='+')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1+x2);
i++;
}
else if (post[i] =='-')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1-x2);
i++;
}
else if (post[i] =='*')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1*x2);
i++;
}
else if (post[i] =='/')
{
x2 = stack.pop();
x1 = stack.pop();
stack.push(x1/x2);
i++;
}
}
return stack.gettop();
}
小注:
error C2258: illegal pure syntax, must be '= 0'
在VC 6.0中這樣的錯誤一般是因爲定義常量不正確導致的,在類中不能直接給變量賦值,也不能在類中定義一個const量,如:class MyStack
{
public:
……
const static int MAXSIZE =100;
}
這樣就會出錯,所以必須把上面寫成下面格式,
const static int MAXSIZE =100;
class MyStack{
public:
……
}
這樣錯誤就會避免~