C++作四則運算的MFC計算器(二)棧轉換和計算後綴表達式

上篇寫了MFC界面搭建,這篇就寫實現計算。涉及到數據結構,對新手很不友好。html

雖然是MFC程序,可是能靈活地分離後臺代碼,自行構建控制檯程序。數組

上篇文章連接:C++作四則運算的MFC計算器(一)MFC界面建立 數據結構

概要:ide

  1. 中綴表達式與後綴表達式
  2. 棧的相關實現
  3. 用棧將中綴表達式轉換成後綴表達式
  4. 棧計算後綴表達式 
  5. 等號按鈕功能-計算結果顯示

中綴表達式與後綴表達式函數

中綴:(60-20)/(5-1)。小學就學的東西post

後綴:60 20 – 5 1 - /,爲增長可讀性,以「#」作分隔符,60#20#-#5#1#-#/。編碼

後綴計算:從左到右遇到符號就計算符號左邊的兩個數並寫上新值,即優先的運算符相對在左。上例中遇到第一個‘-’算60-20得40,遇到第二個「-」計算5-1得4,遇到「/」計算30/3的10,結果是10。url

對比:中綴式人看起來方便,後綴式沒有括號,計算順序從前到後,計算機操做起來簡單。spa

棧的相關實現3d

輸入的值都是字符,因此須要一個字符結構的棧;在計算數時就須要一個處理數字結構的棧。

字符和數值的棧結構體分別命名SqStack和SqStackN。

而後實現棧初始化、進棧、出棧等棧操做函數。

在工程中,同時把棧結構體和操做函數聲明在新建的頭文件xxx.h中,或者工程中其餘頭文件如stdafx.h,函數體的實如今新建的xxx.cpp中,其餘cpp。

 

 1 struct SqStack {
 2     char data[maxsize];
 3     int top;
 4 };
 5 struct SqStackN {
 6     double data[maxsizen];
 7     int top;
 8 };
 9 //棧操做函數—字符
10 void initStack(SqStack *&s);
11 bool Push(SqStack *&s, char e);
12 bool Pop(SqStack *&s, char &e);
13 bool GetTop(SqStack *s, char &e);
14 void DestroyStack(SqStack *&s);
15 bool StackEmpty(SqStack *s);
16 //棧操做函數—數字
17 void initStack(SqStackN *&s);
18 bool Push(SqStackN *&s, double e);
19 bool Pop(SqStackN *&s, double &e);
20 bool GetTop(SqStackN *s, double &e);
21 void DestroyStack(SqStackN *&s);
22 bool StackEmpty(SqStackN *s);
23 
24 //後綴表達式轉換函數
25 void trans(char* exp, char postexp[]);
26 //計算後綴表達式函數
27 double calculate(char* postexp);
頭文件主要聲明

 

 1 void initStack(SqStack *&s) {
 2     s = new SqStack();
 3     s->top = -1;
 4 }
 5 bool Push(SqStack *&s, char e) {
 6     if (s->top == maxsize-1)
 7         return false;
 8     s->top++;
 9     s->data[s->top] = e;
10     return true;
11 }
12 bool Pop(SqStack *&s, char &e) {
13     if (s->top == -1)
14         return false;
15     e = s->data[s->top];
16     s->top--;
17     return true;
18 }
19 bool GetTop(SqStack *s, char &e) {
20     if (s->top == -1)
21         return false;
22     e = s->data[s->top];
23     return true;
24 }
25 void DestroyStack(SqStack *&s) {
26     free(s);
27 }
28 bool StackEmpty(SqStack *s) {
29     return (s->top == -1);
30 }
31 
32 void initStack(SqStackN *& s){
33     s = new SqStackN();
34     s->top = -1;
35 }
36 
37 bool Push(SqStackN *& s, double e)
38 {
39     if (s->top == maxsizen - 1)
40         return false;
41     s->top++;
42     s->data[s->top] = e;
43     return true;
44 }
45 
46 bool Pop(SqStackN *& s, double & e)
47 {
48     if (s->top == -1)
49         return false;
50     e = s->data[s->top];
51     s->top--;
52     return true;
53 }
54 
55 bool GetTop(SqStackN * s, double & e)
56 {
57     if (s->top == -1)
58         return false;
59     e = s->data[s->top];
60     return true;
61 }
62 
63 void DestroyStack(SqStackN *& s){
64     free(s);
65 }
66 
67 bool StackEmpty(SqStackN * s)
68 {
69     return (s->top == -1);
70 }
cpp函數定義

 

用棧將中綴表達式轉換成後綴表達式

從左向右掃描中綴,遇到數字就添加到後綴中,遇到運算符進行棧處理,而棧的處理依賴於運算符優先級,優先級高的靠近棧頂。結束後後綴式還是字符數組。

寫個函數tans(),有2個參數char * exp和char postexp[ ],

先初始化一個字符棧指針s,char e用來操做棧頂元素,int p做爲postexp數組的下表。寫個循環掃描exp

while (*exp != '\0') {switch(*exp){case:case:case:default}......}

掃描到數字字符時直接加到後綴式中,並加上 ‘ # ’ 以分割。

其餘狀況無非是+、-、*、/、(、)這6個符號。

(、)優先級最高,在括號之間的運算符必定比括號以外的優先運算,遇到 ‘ ( ’ 即進棧,遇 ‘ ) ’ 即出棧棧頂元素直到出來的是 ‘ ( ’ 。所以棧中不會有 ‘ ) ’ 。

*、/優先級其次,先判斷棧頂是什麼,棧頂是*、/則將其出棧值後綴式,棧頂是+、-則將 ‘ * ’ 或 ‘ / ’ 進棧。

+、-優先級最低,這是棧頂元素無論是+-*/都出棧至後綴式,但棧頂是 ‘ ( ’ 時就不須要出棧,‘ ( ’能夠看做是一個新的運算起點,將+或-進棧便可。

exp掃描後棧可能還會有運算符,將剩下的都出棧至後綴式。再爲後綴式加結束標識 ‘\0’ ,銷燬棧釋放空間。

 1 void trans(char* exp,char postexp[]) {  2     char e;  3     SqStack *s;    initStack(s);    // 即SqStack s = new SqStacck()
 4     int p = 0;//postexp的下表
 5     while (*exp != '\0') {  6         switch (*exp)  7  {  8         case '+':  9         case '-': 10             while (!StackEmpty(s)) { 11  GetTop(s, e); 12                 if (e != '(') { 13                     postexp[p++] = e; 14  Pop(s, e); 15  } 16                 else
17                     break; 18  } 19             Push(s, *exp); 20             exp++;break; 21         case '*': 22         case '/': 23             while (!StackEmpty(s)) { 24  GetTop(s, e); 25                 if (e == '*' || e == '/') { 26                     postexp[p++] = e; 27  Pop(s, e); 28  } 29                 else
30                     break; 31  } 32             Push(s, *exp); 33             exp++;break; 34         case '(': 35             Push(s, *exp); 36             exp++;break; 37         case ')': 38  Pop(s, e); 39             while (e != '(') { 40                 postexp[p++] = e; 41  Pop(s, e); 42  } 43             exp++;break; 44         default: 45             while (*exp >= '0'&&*exp <= '9') { 46                 postexp[p++] = *exp; 47                 exp++; 48  } 49             postexp[p++] = '#'; 50             break; 51  } 52  } 53     while (!StackEmpty(s)) { 54  Pop(s, e); 55         postexp[p++] = e; 56  } 57     postexp[p] = '\0'; 58  DestroyStack(s); 59 }
轉換函數trans()

棧計算後綴表達式 

這一功能相對簡單些,掃描後綴式,

遇到表示數字的字符時,例如 ‘ 6 ’ ,利用它與 ‘ 0 ’ 編碼之間的差獲得數字,‘ 6 ’ - ‘ 0 ’ = 6 ,乘10實現位數值。獲得的數值放入棧裏。

遇到運算符時直接出棧兩個元素,此時這兩個元素必定是數字,第一個出棧的作運算符右值,第二個作左值,順序不能反,結果還要入棧以進行下一步運算。

遇到 ‘ / ’ 時還要判斷棧頂是不是0,被除數可不能是0啊。

最後棧中就是運算結果,出棧做爲返回值。

 1 double calculate(char* postexp) {  2     double a, b,c,d,e;  3     SqStackN *o; initStack(o);  4     while (*postexp != '\0') {  5         switch (*postexp)  6  {  7         case '+':  8  Pop(o, a);  9  Pop(o, b); 10             c = b + a; 11  Push(o, c); 12             break; 13         case '-': 14  Pop(o, a); 15  Pop(o, b); 16             c = b - a; 17  Push(o, c); 18             break; 19         case '*': 20  Pop(o, a); 21  Pop(o, b); 22             c = b * a; 23  Push(o, c); 24             break; 25         case '/': 26  Pop(o, a); 27  Pop(o, b); 28             if (a != 0) { 29                 c = b / a; 30  Push(o, c); 31                 break; 32  } 33             else { 34                 exit(0); 35  } 36             break; 37         default: 38             d = 0; 39             while (*postexp >= '0'&&*postexp <= '9') { 40                 d = d * 10 + (*postexp - '0'); 41                 postexp++; 42  } 43  Push(o, d); 44             break; 45  } 46         postexp++; 47  } 48  GetTop(o, e); 49  DestroyStack(o); 50     return e; 51 }
計算後綴式函數

等號按鈕功能-計算結果顯示

 運算功能已經實現了,可是要講功能綁定到 ‘ = ’ 還有最後一道坎~

MFC文本編輯框的類型是CString,要想轉換成char[]有點讓人頭大。

須要幾個變量,輸入的算式char exp[50],後綴式char postexp[50],運算結果result。

CString轉換爲char[]直接上代碼吧: ::wsprintfA(exp, "%ls", (LPCTSTR)editv); 

double轉CString代碼: resultv.Format(_T("%.5lf"), result); 

 

 1 void CMFCcalculationDlg::OnBnClickedButton19()  2 {  3     // TODO: 等號按鈕
 4     char exp[50];  5     char postexp[50];  6     double result;  7     UpdateData(true);  8     ::wsprintfA(exp, "%ls", (LPCTSTR)editv);  9  trans(exp, postexp); 10     result = calculate(postexp); 11     resultv.Format(_T("%.5lf"), result); 12     //resultv.Format(TEXT("%lf\n%.2lf"), result);
13     UpdateData(false); 14 }
等號按鈕功能

 

運行結果:

 

程序在未發佈前比較大,100多M,包含了不少不用的文件,在資源管理器裏仍是隱藏的。發佈後的程序只有幾M。

程序發佈:將Debug改爲Release,運行即發佈,以後項目同級目錄裏有Release文件夾,裏面就是你的應用程序。

相關文章
相關標籤/搜索