計算器我們都實現了很多了,但是,我們寫的計算器都是求解兩個操作數的,並不能求解一個表達式,如今棧已經學完了,那麼我們可不可以使用棧來實現表達式的求解呢?
我們數學上求解一個表達式是如何進行的,有括號的先求括號內部的,之後先算乘除,再算加減。現在如果來實現一個這樣可以求解表達式的計算器,怎樣進行呢?
首先是將中綴表達式轉化爲後綴表達式,具體的規則如下:
1、遇到操作數,直接輸出;
2、棧爲空時,遇到運算符,入棧;
3、遇到左括號,將其入棧;
4、遇到右括號,執行出棧操作,並將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出;
5、遇到其他運算符’+”-”*”/’時,彈出所有優先級大於或等於該運算符的棧頂元素,然後將該運算符入棧;
6、最終將棧中的元素依次出棧,輸出。
之後就是後綴表達式的求解了,大致是這樣的:
掃描後綴表達式, 如果是數字,則讓其進棧; 若爲操作符,則從棧中取出兩個操作數,先取出的作爲右操作數,後取出的作爲左操作數,然後進行該操作符的運算,並使其結果入棧。 重複上述過程,直至表達式掃描完成。 最終棧中只留一個元素,就是表達式結果。
下面是具體的實現代碼:
#include<iostream>
using namespace std;
#include<assert.h>
#include<stack>
//獲取操作符的優先級
int GetPriority(char ch, int flag)//flag爲1時表示棧內優先級 flag爲0表示棧外優先級
{
if (ch == '+' || ch == '-')
{
if (flag)
{
return 3;
}
else
{
return 2;
}
}
else if (ch == '*' || ch == '/' || ch == '%')
{
if (flag)
{
return 5;
}
else
{
return 4;
}
}
else if (ch == '(')
{
if (flag)
{
return 1;
}
else
{
return 6;
}
}
else if (ch == ')')
{
if (flag)
{
return 6;
}
else
{
return 1;
}
}
}
//中綴表達式轉化後綴表達式
void InfixToPostfix(char *dest, char*src)
{
assert(dest);
assert(src);
stack<char> s;//保存操作符,使其按照優先級從大到小輸出
char* _cur = src;//用一個指針指向中綴表達式
char* _temp = dest;//用指針指向存儲後綴表達式的空間
while (*_cur != '\0')
{
if (*_cur >= '0' && *_cur <= '9')//如果是數字字符,那麼保存
{
*_temp++ = *_cur;
_cur++;
continue;
}
//如果是操作符,那麼分情況討論
else if (*_cur == '+' ||* _cur == '-' || *_cur == '*' || *_cur == '/' || *_cur == '%' || *_cur == '(' || *_cur == ')')
{
if (s.empty())//
{
s.push(*_cur);
_cur++;
}
else
{
if (*_cur == ')')
{
while (s.top() != '(')
{
*_temp++ = s.top();
s.pop();
}
s.pop();//刪除棧頂的‘(’
*_cur++;
}
//如果當前操作符的優先級大於棧頂元素的優先級,將當前操作符入棧
if (GetPriority(*_cur, 0) > GetPriority(s.top(), 1))
{
s.push(*_cur);
_cur++;
}
else
{
while (!s.empty() && GetPriority(*_cur, 0) < GetPriority(s.top(), 1))
{
*_temp++ = s.top();
s.pop();
}
s.push(*_cur);
_cur++;
}
}
}
else//跳過空格
{
*_temp++ = *_cur++;
}
}
//將棧內剩餘元素放入表達式
while (!s.empty())
{
*_temp++ = s.top();
s.pop();
}
}
//後綴表達式求值(計算器)
int Calculate(char *_postfix,char*_infix)
{
InfixToPostfix(_postfix, _infix);
stack<int> s;//注意前後兩個棧的使用用途不同,實例化也不同
char*_cur = _postfix;
int temp = 0;//保存數字字符轉化後的數字
int res = 0;//保存運算結果
while (*_cur != '\0')
{
if (*_cur >= '0'&&*_cur <= '9')
{
res = 0;
while (!isspace(*_cur) && *_cur >= '0'&&*_cur <= '9')
{
temp = *_cur - '0';//將數字字符轉化爲數字
res = res * 10 + temp;// 例如:12
_cur++;
}
s.push(res);
}
else if (*_cur == '+' || *_cur == '-' || *_cur == '*' || *_cur == '/' || *_cur == '%')
{
int right = s.top();//先取出來的是右操作數
s.pop();
int left = s.top();
s.pop();
switch (*_cur)
{
case '+':
s.push(left + right);
break;
case '-':
s.push(left - right);
break;
case '*':
s.push(left * right);
break;
case '/':
if (right)
{
s.push(left / right);
break;
}
case '%':
s.push(left % right);
break;
}
_cur++;
}
else//跳過空格
{
_cur++;
}
}
if (!s.empty())
{
res = s.top();
s.pop();
return res;
}
}
void FunTest()
{
char* _infix = "12 * (3 + 4) - 6 + 8 / 2 ";
char _postfix[20] = {};
int result = Calculate(_postfix, _infix);
cout <<result << endl;
}
int main()
{
FunTest();
return 0;
}