簡單計算機——逆波蘭表達式
阿新 • • 發佈:2017-09-28
emp 內部 family -- bool logs 賦值 加減 是否為空
逆波蘭數:逆波蘭數由兩部分組成(操作數,操作符)——是波蘭表達式的一種,即操作符在操作數的後面。
形式:A+B*C-D = ABC*D-;
(A+B)*C-D = AB+C*D-;
既然我們知道了,後綴表達式那我們表達式是唯一的嗎?我們來看一組數據:
例如:(A+B)*C-D 和 C*(A+B)-D;
很顯然第二個的表達式為:C*AB+D-;雖然對最後的結果無影響,但我們需要知道逆波蘭的多樣性。
註意事項:
1、如果出現1+23 = 123+,該如何判斷它的數值呢?
可以利用分割符來進行很好的輔助性理解,例如1+23 = 1#23#+,這樣可以完美的解決此問題。
2、存在括號的時候該如何處理?
其一:是‘(’直接壓入,‘)’時,將兩者之間的運算符彈出,壓入後綴表達式。
其二:遇到‘(’開辟一個新的運算符棧,‘)’時,當前棧內運算符彈出,壓入後綴表達式。
算法:
1、中綴表達式——逆波蘭表達式的轉變。
- 準備一個棧一個鏈表,鏈表用來存操作數,棧用來存操作符。
- 如果為操作數,我們繼續判斷它的下一位是否也為操作數,是——則繼續壓入,否——壓入分隔符(“#”)。同時判斷字符棧中,是否為“*”,“/”,字符彈出,壓入數值鏈表。
- 如果為操作符,直接壓入字符棧。
- 如果‘(’,重新開辟一個新字符棧,其它操作相同。
- 如果‘ )’,將當前字符棧內部的字符逐個彈出,壓入數值鏈表。
2、逆波蘭求值。
- 準備一個棧,用來逐個求當前值。
- 依次取出數值鏈表的第一個值。
- 根據加減乘除運算做出相應的操作,即取出當前棧的前兩個值,做運算符操作。
- 如果是操作數,我們繼續判斷它的下一位是否也為操作數,是——n*10+char-‘0’,否——壓入棧中;
- 最後的到棧頂元素,即為運算後的值。
核心代碼:
1、中綴表達式——逆波蘭表達式的轉變。
bool is_char(char c)//判斷是否為操作符
{
return c == ‘-‘ || c == ‘+‘ || c == ‘*‘ || c == ‘/‘;
}
void change()//表達式的轉化
{
char c;
int i = 0, j = 0;//i遍歷輸入的字符,j不同層數的字符棧
while ((c = original[i++]) != ‘\0‘)
{
if (is_char(c))//是字符
one[j].push(c);
else if (is_number(c))//是數字
{
int x = i;//
while (is_number(c))
{
sconed.push_back(c);
if (is_number(c = original[x++]))//是數值,則數組往後移動一位(確保下一步能讀取字符)
i++;
}
sconed.push_back(‘#‘);//分隔符
if (!one[j].empty())//判斷是否為空
if (one[j].top() == ‘*‘ || one[j].top() == ‘/‘)//高階運算,直接取出,壓入數值鏈表
{
sconed.push_back(one[j].top());
one[j].pop();
}
}
else if (c == ‘)‘)
{
Dum(j);//多余的運算符賦值
j--;//回到上一層的字符棧
}
else
j++;//新的字符棧
}
Dum(j);
}
void Dum(int j)//多余的運算符逐個壓入數值鏈表
{
while (!one[j].empty())
{
sconed.push_back(one[j].top());
one[j].pop();
}
}
View Code
2、逆波蘭求值。
void Do_it(std::stack<int> &mc)
{
while (!sconed.empty())//不為空時。
{
char mid = sconed.front();//臨時存儲字符
sconed.pop_front();//壓出
switch (mid)//判斷
{
int a, b;
case‘-‘:
b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前兩個數值進行減法運算。
mc.push(a - b);
break;
case‘+‘:
b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前兩個數值進行加法運算。
mc.push(a + b);
break;
case‘*‘:
b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前兩個數值進行乘法運算。
mc.push(a * b);
break;
case‘/‘:
b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前兩個數值進行除法運算。
if (b == 0)//分母不能位0
{
is_right = false;
return;
}
else
mc.push(a / b);
break;
default://獲得數值
{
int sum = 0;
if (is_number(mid))
{
while (is_number(mid))
{
sum = sum * 10 + mid - ‘0‘;//字符到數字的改變
mid = sconed.front();
if (is_number(mid))
sconed.pop_front();
}
mc.push(sum);
}
}
}
}
}
Do_it
3、GitHub源碼;
簡單計算機——逆波蘭表達式