c语言栈实现表达式求值
2016-08-12 17:03
302 查看
算术四则运算规则
先乘除,后加减从左算到右
先括号内后括号外
表达式组成
任何一个表达式都有操作数、运算符和界定符组成。操作数即可以是常量,也可以是被说明为变量或常量的标识符。
运算符可以分为算术运算,关系运算和逻辑运算符。
界定符有左右括号和结束符等。
若把运算符和界定符统称为算符,他们构成的集合命名为OP.则任意两个相继出现的算符a和b之间的有限关系至多是下面的三种之一:
a < b a的优先权高于b
a < b a的优先权低于b
a = b a的优先权等于b
OP的优先权关系如下表(0表示不存在)
+ | - | * | / | ( | ) | # | |
---|---|---|---|---|---|---|---|
+ | > | > | < | < | < | > | > |
- | > | > | < | < | < | > | > |
* | > | > | > | > | < | < | < |
/ | > | > | > | > | < | < | < |
( | < | < | < | < | < | = | 0 |
) | > | > | > | > | 0 | > | > |
# | < | < | < | < | < | 0 | = |
这一对“#”表示一个表达式求值完成
“(”=“)”表示当一对括号相遇时表示括号内已运算完成。
“)”和“(”、“#”和“(”、“(”和“#”无法相继出现如果出现则表达式出现语法错误。
为实现优先算法,可以使用两个工作栈,一个是OPTR,用于寄存运算符,一个是OPND,用于寄存运算数和运算结果。
##算法基本思路
1.首先置操作数栈为空栈,表达式起始符为“#”为栈底元素。
2.依次读入表达式中的每个字符,若是操作数则进OPND栈,若是运算符则和OPTR栈的栈顶运算符比较优先权作相应操作:
1. 栈顶元素优先权低:运算符入栈,并重新输入
2. 优先权一样:运算符弹栈,并重新输入
3. 栈顶元素优先权高:弹栈,计算,结果入栈
直至整个表达式求值完毕(OPTR栈顶元素和当前读入的字符均为“#”)
##代码实现
参考严蔚敏老师的《数据结构》(c语言版)的实现思路,代码由自己完成
#include"int_sp_stack.c" #include <ctype.h> /* 存储运算符和界限符 */ char OP[7] = {'+', '-', '*', '/', '(', ')', '#'}; /* OP的优先级表 */ char pre[][7] ={ {'>', '>', '<', '<', '<', '>', '>'}, {'>', '>', '<', '<', '<', '>', '>'}, {'>', '>', '>', '>', '<', '>', '>'}, {'>', '>', '>', '>', '<', '>', '>'}, {'<', '<', '<', '<', '<', '=', '0'}, {'>', '>', '>', '>', '0', '>', '>'}, {'<', '<', '<', '<', '<', '0', '='} }; /* 输入函数 * 若输入运算数(可以是多位数),存到指针n中,并返回true * 若输入运算符,存到指针c中,并返回false */ int get_input(int *n) { *n = 0; char ch = getchar(); /* 消除\n */ getchar(); if(!isdigit(ch)) { *n = ch; return true; } do { *n = (*n) * 10 + (ch - '0'); ch = getchar(); /* 消除\n */ getchar(); } while(ch != ' '); return false; } /* 判断输入运算符和栈顶运算符的优先级 * 若栈顶运算符的优先级高返回'>' * 若栈顶运算符的优先级低返回'<' * 若栈顶运算符和输入运算符的优先级相等返回'=' * 否则返回'0' */ char precmp(char s_top, char ch) { int i, j; switch(s_top) { case '+':i = 0;break; case '-':i = 1;break; case '*':i = 2;break; case '/':i = 3;break; case '(':i = 4;break; case ')':i = 5;break; case '#':i = 6;break; default:i =0;break; } switch(ch) { case '+':j = 0;break; case '-':j = 1;break; case '*':j = 2;break; case '/':j = 3;break; case '(':j = 4;break; case ')':j = 5;break; case '#':j = 6;break; default:j =0;break; } return pre[i][j]; } /* 根据两个栈的弹栈内容计算 */ int compute(int a, char theta, int b) { int result; switch(theta) { case '+':result = a + b;break; case '-':result = a - b;break; case '*':result = a * b;break; case '/':result = a / b;break; } return result; } /* 算数表达式求值的算符优先算法 * 设OPTR和OPND分别为运算符栈和运算数栈 */ int evaluate_expression() { /* 输入元素 */ int *elem = (int *)malloc(sizeof(*elem)); /* 输入元素类型 * type = true表示输入为运算符 * type = false表示输入为运算数 */ int type; /* 出栈元素 */ int *x = (int *)malloc(sizeof(*x)); /* 运算出栈元素 */ int *theta = (int *)malloc(sizeof(*theta)); int *a = (int *)malloc(sizeof(*a)); int *b = (int *)malloc(sizeof(*b)); /* 操作符栈 */ int_sp_stack OPTR = (int_sp_stack)malloc(sizeof(int_stack)); /* 操作数栈 */ int_sp_stack OPND = (int_sp_stack)malloc(sizeof(int_stack)); OPTR = stack_init(OPTR); OPND = stack_init(OPND); push(OPTR, '#'); type = get_input(elem) ; *x = '#'; while(*elem != '#' || *x != '#') { /* 输入不是运算符 */ if(!type) { push(OPND, *elem); type = get_input(elem); } else { get_top(OPTR, x); switch(precmp(*x, *elem)) { case '<': push(OPTR, *elem); type = get_input(elem); get_top(OPTR, x); break; case '=': pop(OPTR, x); get_top(OPTR, x); type = get_input(elem); break; case '>': pop(OPTR, theta); pop(OPND, b); pop(OPND, a); push(OPND, compute(*a, *theta, *b)); get_top(OPTR,x); break; } } } get_top(OPND, x); stack_destroy(OPTR); stack_destroy(OPND); return *x; } int main() { int x = evaluate_expression(); printf("x = %d", x); return 0; }
注意:对于getchar()函数来说,是从缓存流中获取一个字符并返回的.例如连续调用两次getchar()函数
char a = getcahr(); char b = getchar();
当执行第一个getchar()函数时,输入x并以回车键结束输入,这时当程序调用第二个getchar()函数时,回直接从缓存那取得换行符’\n’返回,也就是b=’\n’,而不会终止程序,等待从键盘再输入一个字符.想要从键盘输入一个字符赋给b,应先消除缓存中’\n’的影响,较简单的方法是在两个getchar()函数之间再调用一次getchar()函数.
上述程序,采用的是之前顺序栈的实现接口,程序正确执行的输入格式:例如计算(52 - 3 + 1) * 10
( 5 2 "空格" - 3 "空格" - 1 "空格" ) * 1 0 "空格" # "回车"
结果截图:
改进输入:把int get_input(int n)函数改成下面的形式后,程序运行时输入格式为:例如计算(52 - 3 + 1) 10
int get_input(int *n) { *n = 0; char ch = getchar(); /* 消除\n */ //getchar(); if(!isdigit(ch)) { *n = ch; getchar(); return true; } do { *n = (*n) * 10 + (ch - '0'); ch = getchar(); /* 消除\n */ //getchar(); } while(ch != '\n'); return false; }
( 52 - 3 - 1 ) * 10 # "回车"
结果截图:
相关文章推荐
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 栈实现表达式求值
- 字符串表达式校验&求值(C#实现)
- 实现简单的表达式求值
- 表达式求值算法的实现
- C++实现表达式求值
- 利用栈实现的后缀形式的算术表达式的求值的c++程序
- C++实现任意表达式求值(栈)
- 数据结构习作之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java) (技术含量少许)
- 使用双栈实现表达式求值
- 顺序栈实现表达式求值
- 在单链表的基础上用c++实现的链栈,并使用进制转换,表达式求值两个小程序来测试
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java) (转载)
- 用静态栈数据结构实现表达式求值
- 用c++实现中序表达式求值
- 表达式求值程序(用栈实现)
- Linux系统下用C语言实现浮点数四则运算表达式的求值
- 字符串表达式求值 C#实现
- 数据结构课程设计---------用栈来实现表达式求值