【数据结构】支持四则混合运算的计算器(转)
1.給出兩個數,用戶再指定操作符,要求計算結果,這實現起來很容易;
??2.多個數,但只涉及同一優先級的操作符,做起來也很容易;
??3.多個數,不同優先級的操作符,怎么辦呢?
想想就頭痛,不過還好前人已經為我們留下了很多解決這個問題的方法。通過逆波蘭表達式是解決這個問題很流行的一種方式。
?
一、什么是逆波蘭表達式?
我們一般使用的表達式,形如1+2*3,被稱為中綴表達式,轉換為后綴表達式即為:1 2 3 * +,而后綴表達式也就是我們所說的逆波蘭表達式。
逆波蘭表達式計算起來非常方便:遇操作數入棧,遇操作符則彈出棧頂兩個元素進行計算并將結果推入棧中,直至結束。上面的表達式的計算過程可以用下圖表示:
?
也正因為逆波蘭的方便性,使它成為了計算器的普遍實現方式。
二、四則混合運算計算器
既然思路已經清晰了,那么我們的計算器可以分兩步走:
1.將表達式轉換為逆波蘭形式
2.逆波蘭表達式求值。
?生成逆波蘭表達式:
將一般中綴表達式轉換為逆波蘭表達式有如下轉換過程:
(1)首先構造一個運算符棧,此運算符在棧內遵循越往棧頂優先級越高的原則。
(2)讀入一個用中綴表示的簡單算術表達式,為方便起見,設該簡單算術表達式的右端多加上了優 先級最低的特殊符號“#”。
(3)從左至右掃描該算術表達式,從第一個字符開始判斷,如果該字符是數字,則分析到該數字串 的結束并將該數字串直接輸出。
(4)如果不是數字,該字符則是運算符,此時需比較優先關系。
做法如下:將該字符與運算符棧頂的運算符的優先關系相比較。如果,該字符優先關系高于此運算符 棧頂的運算符,則將該運算符入棧。倘若不是的話,則將棧頂的運算符從棧中彈出,直到棧頂運算符的優先級低于當前運算符,將該字符入棧。
(5)重復上述操作(3)-(4)直至掃描完整個簡單算術表達式,確定所有字符都得到正確處理,我們便可以將中綴式表示的簡單算術表達式轉化為逆波蘭表示的簡單算術表達式。
????????????而上面提到的運算符優先級如下:
| 操作符 | # | ^ | *,/,% | +,-? | ( | ) |
| isp(棧內優先級) | 0 | 7 | 5 | 3 | 1 | 8 |
| icp(棧外優先級) | 0 | 6 | 4 | 2 | 8 | 1 |
下面是程序化算法流程:
1、建立運算符棧stackOperator用于運算符的存儲,壓入'\0'。
2、預處理表達式,正、負號前加0(如果一個加號(減號)出現在最前面或左括號后面,則該加號 (減號)為正負號) 。
3、順序掃描表達式,如果當前字符是數字(優先級為0的符號),則直接輸出該數字;如果當前字 符為運算符或括號(優先級不為0的符號),則判斷第4點?。
4、若當前運算符為'(',直接入棧;
若為')',出棧并順序輸出運算符直到遇到第一個'(',遇到的第一個'('出棧但不輸出;
若為其它,比較stackOperator棧頂元素與當前元素的優先級:
如果 棧頂元素 >= 當前元素,出棧并順序輸出運算符直到 棧頂元素 < 當前元素,然后當前元素入棧;
如果 棧頂元素 < 當前元素,直接入棧。
5、重復第3點直到表達式掃描完畢。
6、順序出棧并輸出運算符直到棧頂元素為'\0'?!?/p>
?
a.預處理表達式,對于一元+,-在前面加0:
///<summary>????????///處理正負號
?????????///</summary>
????????///<param?name="exp"></param>
????????///<returns></returns>
privatestaticstringFormatExp(stringexp)
????????{
????????????var?result?=exp.Trim().Replace("",?"");
????????????if(result[0]?=='+'||result[0]?=='-')
????????????{
????????????????result?="0"+result;
????????????}
????????????for(var?i?=0;?i?<result.Length?-1;?i++)
????????????{
????????????????if(result[i]?=='('&&(result[i?+1]?=='+'||result[i?+1]?=='-'))
????????????????{
????????????????????result?=result.Substring(0,?i?+1)?+"0"+result.Substring(i?+1);
????????????????}
????????????}
????????????returnresult;
????????}
?
b.將格式化后的表達式轉換為逆波蘭表達式
///<summary>????????///將解析過后的表達式轉換為逆波蘭表達式(各個語義單元存放在列表中)
????????///</summary>
????????///<param?name="tokens"></param>
????????///<returns></returns>
privatestaticList<string>ToRPNExp(List<string>tokens)
????????{
????????????var?result?=newList<string>();
????????????var?opStack?=newStack<string>();
????????????opStack.Push("\0");
????????????for(var?i?=0;?i?<tokens.Count;?i++)
????????????{
????????????????if(IsOperator(tokens[i]))
????????????????????result.AddRange(HandleOperator(opStack,?tokens[i]));
????????????????elseresult.Add(tokens[i]);
????????????}
????????????while(opStack.Peek()?!="\0")
????????????{
????????????????result.Add(opStack.Pop());
????????????}
????????????returnresult;
????????}
????????///<summary>
????????///根據操作符的優先級決定入棧還是出棧
????????///</summary>
????????///<param?name="st"></param>
????????///<param?name="op"></param>
????????///<returns></returns>
privatestaticList<string>HandleOperator(Stack<string>st,?stringop)
????????{
????????????var?result?=newList<string>();
????????????if(op?=="(")
????????????{
????????????????st.Push(op);
????????????}
????????????elseif(op?==")")
????????????{
????????????????while(st.Peek()?!="(")
????????????????{
????????????????????result.Add(st.Pop());
????????????????}
????????????????st.Pop();
????????????}
????????????else
????????????{
????????????????var?priority1?=IcpPriority[op];
????????????????var?priority2?=IspPriority[st.Peek()];
????????????????while(priority2?>=priority1)
????????????????{
????????????????????result.Add(st.Pop());
????????????????????priority2?=IspPriority[st.Peek()];
????????????????}
????????????????st.Push(op);
????????????}
????????????returnresult;
????????}
?
求值:
///<summary>????????///進行計算
????????///</summary>
????????///<param?name="tokens"></param>
????????///<returns></returns>
privatestaticdoubleDoCalc(List<string>tokens)
????????{
????????????var?st?=newStack<double>();
????????????foreach(var?token?intokens)
????????????{
????????????????if(!IsOperator(token))
????????????????{
????????????????????//操作數入棧
st.Push(double.Parse(token));
????????????????}
????????????????else
????????????????{
????????????????????//操作符從棧頂取出兩個元素進行計算,并將結果推入棧中
var?operand1?=st.Pop();
????????????????????var?operand2?=st.Pop();
????????????????????switch(token)
????????????????????{
????????????????????????case"+":
????????????????????????????st.Push(operand2?+operand1);
????????????????????????????break;
????????????????????????case"-":
????????????????????????????st.Push(operand2?-operand1);
????????????????????????????break;
????????????????????????case"*":
????????????????????????????st.Push(operand2?*operand1);
????????????????????????????break;
????????????????????????case"/":
????????????????????????????st.Push(operand2?/operand1);
????????????????????????????break;
????????????????????????case"^":
????????????????????????????st.Push(Math.Pow(operand2,?operand1));
????????????????????????????break;
????????????????????}
????????????????}
????????????}
????????????//最終棧頂元素即為表達式的值
returnst.Pop();
????????}
轉載于:https://www.cnblogs.com/xuweili/articles/3361084.html
總結
以上是生活随笔為你收集整理的【数据结构】支持四则混合运算的计算器(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新的sublime text已经上传网盘
- 下一篇: 创建DLL动态链接库——声明导出法