C語言 | 計算器實現(中綴表示法/后綴表示法)


————————————————————————————————————————————

實現原理:

每個操作數都被依次壓入棧中,當一個運算符到達時,從棧中彈出相應數目的操作數(對於二元運算符來說是兩個操作數),把該運算符作用於彈出的操作數,並把運算結果再壓入棧中

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

計算器(后綴表達式)

相關知識:

后綴表達式(逆波蘭表示法):在逆波蘭中,所有運算符都跟在操作數后面,如下:(1 - 2) *(4 + 5) 采用逆波蘭表示法表示為:1 2 - 4 5 + *,不需要圓括號,只要知道每個運算符需要幾個操作數就不會引起歧義

實現功能:

輸入后綴表達式,以換行結束,計算四則運算結果。

對於 1 2 - 4 5 + * 來說,首先把1和2壓入到棧中,再用兩者之差-1取代它們;然后將4和5壓入到棧中,再用兩者之和9取代它們。最后從棧中取出棧頂的-1和9,並把它們的積-9壓入到棧頂。到達輸入行的末尾時,把棧頂的值彈出來並打印。

偽代碼:

while 讀入值不為換行時

if 是數字

壓入棧中

else if 是運算符

彈出兩個運算數,計算並壓棧

else 輸入錯誤並退出

end if

讀入值

彈出最終結果並打印

實現代碼:

 

  1 /* 實現功能:輸入后綴表達式,以換行結束,計算四則運算結果 */
  2 /* 這種后綴表示法只需要一個棧就可以了,遇到符號則彈運算數,但是中綴就不一樣 */
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #define OK 1
  6 #define ERROR 0
  7 #define OVERFLOW -2
  8 #define STACK_INIT_SIZE 100
  9 #define STACKINCREAMENT 10
 10 typedef int Status;
 11 typedef char SElemType;
 12 typedef struct
 13 {
 14     SElemType *top;
 15     SElemType *base;
 16     int stacksize;
 17 } SqStack;
 18 Status InitStack(SqStack *s)
 19 {
 20     s->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
 21     if (!s->base) exit(OVERFLOW);
 22     s->top = s->base;
 23     s->stacksize = STACK_INIT_SIZE;
 24     return OK;
 25 }
 26 Status Push(SqStack *s, SElemType e)
 27 {
 28     if (s->top - s->base == s->stacksize)
 29     {
 30         s->base = (SElemType *)realloc(s->base, (s->stacksize + STACKINCREAMENT) * sizeof(SElemType));
 31         if (!s->base) exit(OVERFLOW);
 32         s->top = s->base + s->stacksize;
 33         s->stacksize += STACKINCREAMENT;
 34     }
 35     s->top++;
 36     *(s->top) = e;
 37     return OK;
 38 }
 39 Status Pop(SqStack *s, SElemType *e)
 40 {
 41     if (s->top == s->base) exit(OVERFLOW);
 42     *e = *(s->top);
 43     s->top--;
 44     return OK;
 45 }
 46 Status Empty(SqStack s)
 47 {
 48     if (s.top - s.base == 0)
 49         return OK;
 50     else
 51         return ERROR;
 52 }
 53 int main()
 54 {
 55     SqStack OPND; //OPTR是運算符 OPND是運算數
 56     char c, num1, num2;
 57     InitStack(&OPND);
 58     while((c = getchar()) != '\n')
 59     {
 60         switch(c)
 61         {
 62         case '0':
 63         case '1':
 64         case '2':
 65         case '3':
 66         case '4':
 67         case '5':
 68         case '6':
 69         case '7':
 70         case '8':
 71         case '9':
 72             Push(&OPND, c - '0');
 73             break;
 74         case '+':
 75             Pop(&OPND, &num2);
 76             Pop(&OPND, &num1);
 77             Push(&OPND, num1 + num2);
 78             break;
 79         case '-':
 80             Pop(&OPND, &num2);
 81             Pop(&OPND, &num1);
 82             Push(&OPND, num1 - num2);
 83             break;
 84         case '*':
 85             Pop(&OPND, &num2);
 86             Pop(&OPND, &num1);
 87             Push(&OPND, num1 * num2);
 88             break;
 89         case '/':
 90             Pop(&OPND, &num2);
 91             Pop(&OPND, &num1);
 92             Push(&OPND, num1 / num2);
 93             break;
 94         default:
 95             break;
 96         }
 97     }
 98     while(!Empty(OPND))
 99     {
100         Pop(&OPND, &c);
101         printf("%d ", c);
102     }
103     return OK;
104 }

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

計算器(中綴表示法)

運算符優先級:

+

-

*

/

(

)

#

+

>

>

<

<

<

>

>

-

>

>

<

<

<

>

>

*

>

>

>

>

<

>

>

/

>

>

>

>

<

>

>

(

<

<

<

<

<

=

0

)

>

>

>

>

0

>

>

#

<

<

<

<

<

0

=

執行過程:

在計算 #4+3*(5-10)/5# 時棧中的執行過程如下

步驟

輸入字符

執行操作

OPTR

OPND

1

#

Push(#)

#

  

2

4

Push(4)

#

4

3

+

'#'<'+',Push(+)

# +

4

4

3

Push(3)

# +

4 3

5

*

'+'<'*',Push(*)

# + *

4 3

6

(

'*'<'(',Push(()

# + * (

4 3

7

5

Push(5)

# + * (

4 3 5

8

-

'('<'-',Push(-)

# + * ( -

4 3 5

9

10

Push(10)

# + * ( -

4 3 5 10

10

)

'-'>')',計算並壓入結果

# + * (

4 3 -5

11

  

'('=')',脫括號

# + *

4 3 -5

12

/

'*'>'/'計算並壓入結果

# +

4 -15

13

  

'+'<'/',Push(/)

# + /

4 -15

14

5

Push(5)

# + /

4 -15 5

15

#

'/'>'#',計算並壓入結果

# +

4 -3

16

  

'+'>'#',計算並壓入結果

#

1

17

  

'#'='#',脫括號

  

1

偽代碼:

初始化運算符棧;壓入#;

初始化運算數棧;獲取輸入;

while 獲取輸入不為#或棧頂不為#

if 輸入的是數字

壓入運算數棧

獲取輸入

if 新輸入的也是數字

十位數百位數運算

end if

else

switch 運算符棧頂與當前輸入優先級比較

壓入運算符棧

獲得輸入

彈出運算符棧頂(或#

獲得輸入

彈出運算符棧頂

彈出兩個運算數

計算並將結果壓入運算數棧

//此時不獲取新輸入,該循環輸入的運算符作為c重新進入循環

end if

end while

輸出運算數棧中剩的運算數

實現代碼:

 

  1 /* 只能運算-128~127之間的結果 */
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <math.h>
  5 #define OK 1
  6 #define ERROR 0
  7 #define SPILL -2 //math.h中已有OVERFLOW,則改用SPILL
  8 #define STACK_INIT_SIZE 100
  9 #define STACKINCREAMENT 10
 10 typedef char SElemType;
 11 typedef int Status;
 12 typedef struct
 13 {
 14     SElemType *top;
 15     SElemType *base;
 16     int stacksize;
 17 } SqStack;
 18 Status InitStack(SqStack *s)
 19 {
 20     s->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
 21     if (!s->base)
 22         exit(SPILL);
 23     s->top = s->base;
 24     s->stacksize = STACK_INIT_SIZE;
 25     return OK;
 26 }
 27 Status EmptyStack(SqStack s)
 28 {
 29     if (s.top - s.base == 0)
 30         return OK;
 31     else
 32         return ERROR;
 33 }
 34 Status Push(SqStack *s, SElemType e)
 35 {
 36     if (s->top - s->base == s->stacksize)
 37     {
 38         s->base = (SElemType *)realloc(s->base, (s->stacksize + STACKINCREAMENT) * sizeof(SElemType));
 39         if (!s->base)
 40             exit(SPILL);
 41         s->top = s->base + s->stacksize;
 42         s->stacksize += STACKINCREAMENT;
 43     }
 44     s->top ++;
 45     *(s->top) = e;
 46     return OK;
 47 }
 48 Status Pop(SqStack *s, SElemType *e)
 49 {
 50     if (s->top == s->base)
 51         exit(SPILL);
 52     *e = *(s->top);
 53     s->top--;
 54     return OK;
 55 }
 56 SElemType GetTop(SqStack s)
 57 {
 58     return *(s.top);
 59     // *e = *(s.top);
 60     // return OK;
 61 }
 62 /* 判斷如果是數字則返回OK,運算符返回ERROR,非法輸入則退出 */
 63 Status InputJudge(SElemType c)
 64 {
 65     switch(c)
 66     {
 67     case '0':
 68     case '1':
 69     case '2':
 70     case '3':
 71     case '4':
 72     case '5':
 73     case '6':
 74     case '7':
 75     case '8':
 76     case '9':
 77         return OK;
 78         break;
 79     case '+':
 80     case '-':
 81     case '*':
 82     case '/':
 83     case '(':
 84     case ')':
 85     case '#':
 86         return ERROR;
 87         break;
 88     default:
 89         exit(SPILL);
 90         break;
 91     }
 92 }
 93 /* 當前輸入的運算符和前一個運算符比較優先級 */
 94 SElemType PriorityJudge(SElemType optr1, SElemType optr2)
 95 {
 96     int i, j;
 97     char priorityTable[7][7] =
 98     {
 99         {'>', '>', '<', '<', '<', '>', '>'},
100         {'>', '>', '<', '<', '<', '>', '>'},
101         {'>', '>', '>', '>', '<', '>', '>'},
102         {'>', '>', '>', '>', '<', '>', '>'},
103         {'<', '<', '<', '<', '<', '=', '0'},
104         {'>', '>', '>', '>', '0', '>', '>'},
105         {'<', '<', '<', '<', '<', '0', '='}
106     };
107     switch(optr1)
108     {
109     case '+':
110         i = 0;
111         break;
112     case '-':
113         i = 1;
114         break;
115     case '*':
116         i = 2;
117         break;
118     case '/':
119         i = 3;
120         break;
121     case '(':
122         i = 4;
123         break;
124     case ')':
125         i = 5;
126         break;
127     case '#':
128         i = 6;
129         break;
130     }
131     switch(optr2)
132     {
133     case '+':
134         j = 0;
135         break;
136     case '-':
137         j = 1;
138         break;
139     case '*':
140         j = 2;
141         break;
142     case '/':
143         j = 3;
144         break;
145     case '(':
146         j = 4;
147         break;
148     case ')':
149         j = 5;
150         break;
151     case '#':
152         j = 6;
153         break;
154     }
155     return priorityTable[i][j];
156 }
157 /* 四則運算 */
158 SElemType Calc(SElemType optr, SElemType num1, SElemType num2)
159 {
160     switch(optr)
161     {
162     case '+':
163         return (num1 + num2);
164         break;
165     case '-':
166         return (num1 - num2);
167         break;
168     case '*':
169         return (num1 * num2);
170         break;
171     case '/':
172         return (num1 / num2);
173         break;
174     }
175 }
176 int main()
177 {
178     char c, optr, num1, num2, temp;
179     SqStack OPND, OPTR;
180     InitStack(&OPTR);
181     Push(&OPTR, '#');
182     InitStack(&OPND);
183     c = getchar();
184     while(c != '#' || GetTop(OPTR) != '#')
185     // while(!EmptyStack(OPTR))
186     //嚴蔚敏老師書上的算法是判斷輸入非#或棧頂非#時循環,個人認為判斷運算符棧不為空也可以,當初始化時壓入的#閉合,結束運算
187     {
188         if (InputJudge(c))
189         {
190             Push(&OPND, c - '0');
191             c = getchar();
192             /* 當連續輸入數字時,計算十位數和百位數 */
193             while(InputJudge(c))
194             {
195                 int i = 1;
196                 Pop(&OPND, &temp);
197                 Push(&OPND, temp * pow(10, i) + (c - '0'));
198                 i++;
199                 c = getchar();
200             }
201         }
202         else
203             switch(PriorityJudge(GetTop(OPTR), c))
204             {
205             case '<':
206                 Push(&OPTR, c);
207                 c = getchar();
208                 break;
209             case '=':
210                 Pop(&OPTR, &c);
211                 c = getchar();
212                 break;
213             case '>':
214                 Pop(&OPTR, &optr);
215                 Pop(&OPND, &num2);
216                 Pop(&OPND, &num1);
217                 Push(&OPND, Calc(optr, num1, num2));
218                 break;
219             }
220     }
221     while(!EmptyStack(OPND))
222     {
223         Pop(&OPND, &c);
224         printf("%d\n", c);
225     }
226     return OK;
227 }

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM