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 }

 

 

 

posted @ 2017-05-10 17:46  hugh.dong  阅读(...)  评论(...编辑  收藏