用栈求后缀表达式的值
题目
表达式 (3 + 4) × 2 的后缀形式是 3 4 + 2 ×.
编写 C 程序, 按所示算法, 为使用 整数操作数 及 4 种常用算数运算符 的后缀表达式求值.
算法描述:
从空栈开始, 由左至右扫描后缀表达式.
遇到操作数就将其压入栈.
遇到运算符就弹出栈两次, 对弹出的两个值应用该运算符, 将结果压入栈.
处理完成后, 结果应该留在栈中.
处理的符号 | 操作 | 栈 |
---|---|---|
初始化 | Ø | |
3 | push 3 | 3 |
4 | push 4 | 3, 4 |
+ | pop 4, pop 3 | Ø |
计算 7 = 3 + 4 | ||
push 7 | 7 | |
2 | push 2 | 7, 2 |
× | pop 2, pop 7 | Ø |
计算 14 = 7 × 2 | ||
push 14 | 14 |
栈实现
BOOL 声明在 bool.h 中.
STACK 声明在 stack.h 中.
- /* bool.h */
- #ifndef BOOL_H
- #define BOOL_H 1
- typedef enum { FALSE, TRUE } BOOL;
- #endif
- /* stack.h */
- #ifndef STACK_H
- #define STACK_H 1
- #include "bool.h"
- #define MAX 256
- #define DefEleType(EleType, StackType) \
- typedef struct StackType { \
- EleType arr[MAX]; \
- int top; \
- } StackType
- DefEleType(int, STACK);
- void iniStack(STACK * ps);
- BOOL isEmpty(STACK * ps);
- BOOL isFull(STACK * ps);
- BOOL peak(STACK * ps, int * px);
- BOOL pop(STACK * ps, int * px);
- BOOL push(int x, STACK * ps);
- #endif
- /* stack.c */
- #include "stack.h"
- void iniStack(STACK * ps) {
- ps->top = -1;
- }
- BOOL isEmpty(STACK * ps) {
- return ps->top == -1;
- }
- BOOL isFull(STACK * ps) {
- return ps->top == MAX-1;
- }
- BOOL peak(STACK * ps, int * px) {
- if ( isEmpty(ps) )
- return FALSE;
- (*px) = ps->arr[ps->top];
- return TRUE;
- }
- BOOL pop(STACK * ps, int * px) {
- if ( isEmpty(ps) )
- return FALSE;
- (*px) = ps->arr[(ps->top)--];
- return TRUE;
- }
- BOOL push(int x, STACK * ps) {
- if ( isFull(ps) )
- return FALSE;
- ps->arr[++(ps->top)] = x;
- return TRUE;
- }
arith1
从终端读入表达式, 然后求值.
省略了输入检查, 异常处理等.
- /* arith1.c */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "stack.h"
- BOOL isOperator(const char * op) {
- if ( strlen(op) != 1)
- return FALSE;
- if ( op[0] == '+' || op[0] == '-' || op[0] == '*' || op[0] == '/' )
- return TRUE;
- else
- return FALSE;
- }
- int calc(int a, int b, const char * op) {
- switch ( op[0] ) {
- case '+':
- return a + b;
- case '-':
- return b - a;
- case '*':
- return a * b;
- case '/':
- return b / a;
- default:
- fprintf(stderr, "Error: invalid operator\n");
- exit(EXIT_FAILURE);
- }
- }
- int main(int argc, char ** argv) {
- int a, b;
- int i;
- STACK s;
- iniStack(&s);
- for ( i = 1; i < argc; i++ ) {
- if ( !isOperator(argv[i]) )
- push((int) strtol(argv[i], NULL, 10), &s);
- else {
- pop(&s, &a);
- pop(&s, &b);
- push(calc(a, b, argv[i]), &s);
- }
- }
- if ( peak(&s, &i) )
- printf("result: %i\n", i);
- return EXIT_SUCCESS;
- }
编译:
- **$ gcc arith1.c stack.c -o arith1
注意:
对于乘号 *, 直接输入, 终端 bash 会对 * 做特殊处理, 记得在前面加转义字符 \, 有点烦.
- **$ ./arith1 3 4 + 2 \*
- result: 14
arith2
把乘号 * 换成 ×.
符号 × 超出了 ASCII 的范围, 定义成字符串, 这方法有点愚.
- /* arith2.c */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "stack.h"
- static char ADD[] = "+";
- static char SUB[] = "-";
- static char MUL[] = "×";
- static char DIV[] = "/";
- static char GUARD[] = "";
- static char * OPSET[] = { ADD, SUB, MUL, DIV, GUARD };
- BOOL isOperator(const char * op);
- int calc(int a, int b, const char * op);
- int main(int argc, char ** argv) {
- int a, b;
- int i;
- STACK s;
- iniStack(&s);
- for ( i = 1; i < argc; i++ ) {
- if ( !isOperator(argv[i]) )
- push((int)strtol(argv[i], NULL, 10), &s);
- else {
- pop(&s, &a);
- pop(&s, &b);
- push(calc(a, b, argv[i]), &s);
- }
- }
- if ( peak(&s, &i) )
- printf("result: %i\n", i);
- return EXIT_SUCCESS;
- }
- BOOL isOperator(const char * op) {
- int i = 0;
- while ( strcmp(OPSET[i], "") ) {
- if ( strcmp(op, OPSET[i]) == 0 )
- return TRUE;
- i++;
- }
- return FALSE;
- }
- int calc(int a, int b, const char * op) {
- int flag = 0;
- while ( strcmp(OPSET[flag], op) )
- flag++;
- switch ( flag ) {
- case 0:
- return a + b;
- case 1:
- return b - a;
- case 2:
- return a * b;
- case 3:
- return b / a;
- default:
- exit(EXIT_FAILURE);
- }
- }
编译, 运行:
- **$ gcc arith2.c stack.c -o arith2
- **$ ./arith2 3 4 + 2 ×
- result: 14
arith3
定义一个结构, 把 运算符 和 操作 绑定.
定义了一个 DType 类型, 想着扩展到 double 型数据的计算, 后来发现这不仅仅是换个说明符的问题, 就放弃啦.
... , 无论怎么处理除法都觉得别扭
- /* arith.h */
- #ifndef ARITH_H
- #define ARITH_H 1
- #include "bool.h"
- typedef int DType;
- typedef struct {
- char * tag;
- DType (*calc) (DType a, DType b);
- } OPR;
- BOOL isOperator(const char * opr);
- BOOL isOperand(const char * opd);
- DType calculate(DType a, DType b, const char * op);
- #endif
- /* arith3.c */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "arith.h"
- static DType ADD(DType a, DType b);
- static DType SUB(DType a, DType b);
- static DType MUL(DType a, DType b);
- static DType DIV(DType a, DType b);
- static const OPR OPRSET[] = {
- { "+", ADD }, { "-", SUB },
- { "×", MUL }, { "/", DIV },
- { "", NULL }
- };
- BOOL isOperator(const char * opr) {
- int i = 0;
- while ( strcmp(OPRSET[i].tag, "") ) {
- if ( !strcmp(OPRSET[i].tag, opr) )
- return TRUE;
- i++;
- }
- return FALSE;
- }
- BOOL isOperand(const char * opd) {
- if ( strlen(opd) == 1 ) {
- if ( opd[0] >= '0' && opd[0] <= '9' )
- return TRUE;
- else
- return FALSE;
- }
- int i;
- for ( i = strlen(opd)-1; i > 0; i-- )
- if ( opd[i] < '0' || opd[i] > '9' )
- return FALSE;
- if ( opd[i] == '-'
- || (opd[i] > '0' && opd[i] <= '9') )
- return TRUE;
- return FALSE;
- }
- DType calculate(DType a, DType b, const char * op) {
- int i = 0;
- while ( strcmp(OPRSET[i].tag, op) )
- i++;
- return OPRSET[i].calc(a, b);
- }
- static DType ADD(DType a, DType b) {
- return a + b;
- }
- static DType SUB(DType a, DType b) {
- return b - a;
- }
- static DType MUL(DType a, DType b) {
- return a * b;
- }
- static DType DIV(DType a, DType b) {
- if ( a == 0 ) {
- fprintf(stderr, "Error: %s[%i], %s(), bad operand, %i\n",
- __FILE__, __LINE__, __func__, a);
- exit(EXIT_FAILURE);
- }
- return b / a;
- }
- /* arith_main.c */
- #include <stdio.h>
- #include <stdlib.h>
- #include "bool.h"
- #include "stack.h"
- #include "arith.h"
- BOOL isValid(char * s);
- int main(int argc, char ** argv) {
- int a, b;
- int i;
- STACK s;
- iniStack(&s);
- for ( i = 1; i < argc; i++ ) {
- if ( !isValid(argv[i]) ) {
- fprintf(stderr, "Error: %s[%i], %s(), bad input, %s\n",
- __FILE__, __LINE__, __func__, argv[i]);
- return EXIT_FAILURE;
- }
- }
- for ( i = 1; i < argc; i++ ) {
- if ( !isOperator(argv[i]) ) {
- if ( !push((int) strtol(argv[i], NULL, 10), &s)) {
- fprintf(stderr, "Error: %s[%i], %s(), stack overflow, %s\n",
- __FILE__, __LINE__, __func__, argv[i]);
- return EXIT_FAILURE;
- }
- }
- else {
- if ( pop(&s, &a) && pop(&s, &b) )
- push(calculate(a, b, argv[i]), &s);
- else {
- fprintf(stderr, "Error: %s[%i], %s(), stack underflow, %s\n",
- __FILE__, __LINE__, __func__, argv[i]);
- return EXIT_FAILURE;
- }
- }
- }
- if ( peak(&s, &i) )
- printf("result: %i\n", i);
- return EXIT_SUCCESS;
- }
- BOOL isValid(char * s) {
- if ( isOperator(s) || isOperand(s) )
- return TRUE;
- else
- return FALSE;
- }
编译, 运行:
- **$ gcc arith_main.c arith3.c stack.c -o arith3
- **$ ./arith3 3 4 + 2 ×
- result: 14