常用数据结构栈的应用—-表达式求值
2016-09-13 11:53
330 查看
常用数据结构栈的应用—-表达式求值
常用数据结构栈的应用-表达式求值栈
表达式求值
后缀表达式求值
中缀表达式转后缀表达式
代码示例
栈
栈是常用的数据结构,栈又称堆栈,是一种受限的线性表。其限制是允许在表中的一端进行插入和删除元素。栈中的元素符合后进先出(FILO)的性质。允许插入和删除元素的一端被称为栈顶,另一端被称为栈底。栈有两种关键的操作,分别为出栈和压栈。
栈有两种关键的操作,分别为出栈和压栈。
出栈(pop):它是把栈顶的元素E删除,使E的下一个元素称为新的栈顶,并返回元素E
压栈(push):它是将元素E插入栈顶,使得新插入的元素E称为新的栈顶。
栈的常见的应用主要有:编译器中语法分析的符号匹配、表达式求值、程序的函数调用等。
例如:操作系统中的进程的上下文切换,里面被切换下CPU的进程的现场信息例如寄存器等信息,被保存在堆栈中,等到CPU轮转到该进程时,使用堆栈恢复现场。
表达式求值
表达式求值是栈的一个重要的应用。例如计算器中的加减乘除表达式的计算,都会使用栈来进行求值。表达式的表示方法主要有中缀表示法和后缀表示法。
中缀表示法:操作符号处于两个操作数的中间例如3+4,中缀表达式是符合人们思维的算术表达式方法,中缀表达式通常包含圆括号和方括号。中缀表达式不容易被计算机所理解,因此不太方便使用其进行表达式求值。
中缀表示的例子 1 + 3 * (4 + 5)
后缀表达式:不包含括号,运算符号放在两个运算对象的后面,所有的计算按运算符号出现的顺序,严格的从左向右进行运算(不再需要考虑运算符号的优先规则)。
后缀表达式的例子21+3* 对应中缀表达式为(2+1)*3
后缀表达式求值
使用后缀表达式进行求值的时候,不需要考虑括号和运算符号的优先规则,只需要从左到右进行计算求值即可。后缀表达式的求值过程为:
读入操作数,压入栈中直到读取到操作符
如果读取到为操作符,则将栈顶的前两元素出栈,使用该操作符进行运算,得到计算结果
将计算结果压入栈中
重复1、2、3直到表达式末尾
最后栈中只有一个元素,变为最后的计算结果。将其出栈即可。
例如:
中缀表达式
(2+1)*3
对应的后缀表达式为
21+3*
初始化栈S
读取2和1压入S,此时S为
1,2
读取到操作符+,出栈栈顶两元素得到
1,2,此时栈为空
使用操作符计算两操作数,得到
3(1 + 2 = 3),将
3压入栈S,此时栈S为
3
读入
3,压入栈S,此时栈为
3,3
读取到操作符*,出栈栈顶两元素得到
3,3此时栈S为空
使用操作符*,对两元素进行运算得到
9,将
9压入栈S
读取到表达式尾部
出栈栈顶元素得到
9即为计算结果
计算机通常使用后缀表达式进行表达式求值,但是人们通常输入计算的表达式是中缀表达式,因此在进行表达式求值的时候,应该先将中缀表达式转为后缀表达式,然后使用后缀表达式求出表达式值。后缀表达式求值的过程很简单,已经上面分析过了。现在关键的一步就是中缀表达式转为后缀表达式。
中缀表达式转后缀表达式
中缀表达式转后缀表达式是表达式求值关键的一步,其过程如下:输入中缀表达式IEXP,
输出后缀表达式SEXP
依次读入中缀表达式IEXP,初始化一个栈S用来存放操作符OP。
如果读取的是操作数,直接输出到SEXP。如果为操作符OP,进入step2,如果为空,证明读取到IEXP尾部,则进入step5
判断OP,若为
(,无任何输出,直接压栈
(到S,进入step1;若为
),则出栈S的元素输出到SEXP中直到遇见元素
(,且
(不输出到SEXP中,然后进入step1;若OP不为
(和
),则执行step3
判断栈S的栈顶元素是否为
(,若为
(,则直接将OP压栈到S中;若不为
(,则将栈S的元素出栈输出到SEXP中,直到栈顶元素的优先级小于OP或者栈空,最后进入step4
将OP压入栈S中,进入step1
将栈所有元素输出到SEXP中
例如
IEXP为
(2+1)*3,
初始化一个空栈S.
读取到操作符
(,直接压入栈S,此时栈S为
(、。
读取到操作数
2,则直接输出到SEXP,此时S仍为
(,SEXP为
2
读取到操作符号
+,由于栈S栈顶元素为
(,因此直接将
+,压入栈S中,此时SEXP为
2,栈S为
(、+
读取到操作数
1,直接输出,此时SEXP为
21, 栈S为
(、+。
读取到操作符
),则出栈S的元素直到碰见
(,不输出
(和
),则SEXP为
21+,栈S为空
读取到操作符号
*'压栈到S,此时SEXP仍为
21+,栈S为
*
读取到操作数
3,直接输出到SEXP中,SEXP为
21+3,栈S为
*
读取到文件尾,则出栈S知道栈空,SEXP为
21+3*
最后得到后缀表达式
21+3*
可见,中缀转后缀的关键点在于读取到的操作符为括号的case,栈中的
(保留直到遇见操作符
),否则是不会出栈的。
代码示例
//int栈 #include <stdio.h> #include <malloc.h> #define INCREMENT 20 struct Stack_{ int* a; int capacity; int size; int top; }; int pop_(struct Stack_* stack) { if(stack->size <= 0 || stack->top < 0) return NULL; stack->size--; return stack->a[stack->top--]; } void push_(struct Stack_* stack, int c) { //扩容 if(stack->size <= stack->capacity) { stack->capacity += INCREMENT; int* p = (int*)malloc(sizeof(int) * ( stack->capacity)); int i; int* q; q = p; for(i = 0; i < stack->size; i++) { *(q++) = *(stack->a++); } stack->a = p; } //压栈 stack->size++; stack->top++; stack->a[stack->top] = c; } struct Stack_* initStack_(int capacity) { struct Stack_* stack = (struct Stack_*)malloc(sizeof(struct Stack_)); int* a = (int*)malloc(sizeof(int) * capacity); stack->size = 0; stack->top = -1; stack->a = a; return stack; }; //测试是否字符数组是否存在test字符 int in(char* a, int n, char test) { int i = 0; for(i; i < n; i++) { if(a[i] == test) return 1; } return 0; } //优先级比较 int compare(char a, char b) { if(a == b) return 0; if(a == '+') { if(b == '*' || b == '(' || b == ')') return -1; } if(a == '*') { if(b == '+') return +1; if(b == '(' || b == ')') return -1; } } //中缀表达式转为后缀表达式 char* infix2Suffix(char* infix, int n) { struct Stack* stack = initStack(n); char add = '+'; char mult = '*'; char left = '('; char right = ')'; char op[4] = {'+', '*', '(', ')'}; int i = 0; char *result = (char*)malloc(sizeof(char) * n); char top; int j = 0; for(i; i < n; i++) { char c = infix[i]; //如果读取的字符不为操纵符,为操作数 //直接放入输出字符数组中 if(!in(op, 4, c)) result[j++] = c; else {//开始将操作符压栈 if(stack->size == 0) push(stack, c); else { // if(c != '(' && c != ')') { while(1) { top = pop(stack); if(top == NULL) break; if(top == '(' || compare(c, top) > 0) { push(stack, top); break; } else if (compare(c, top) <= 0) result[j++] = top; } push(stack, c); } if(c == '(') push(stack, c); if(c == ')') { while(1) { top = pop(stack); if(top != NULL && top != '(') result[j++] = top; else break; } } } } } //输出栈中剩余的内容 while(1) { top = pop(stack); if(top == NULL) break; result[j++] = top; } result[j++] = '#'; return result; } //中缀表达式求值 int evaluate(char* infix, int n) { char *suffix = infix2Suffix(infix, n); struct Stack_* stack = initStack_(n); char op[4] = {'+', '*', '(', ')'}; int i = 0; char opnum1, opnum2; char c; while((c = suffix[i++]) != '#') { if(!in(op, 4, c)) push_(stack, (int)c - (int)'0'); else if(in(op, 4, c)){ int opnum1 = pop_(stack); int opnum2 = pop_(stack); int tmp; if(c == '+') tmp = opnum1 + opnum2; if(c == '*') tmp = opnum1 * opnum2; push_(stack, tmp); } } return pop_(stack); } int main() { char infixExp[13] = {'6', '+', '5', '+', '7', '*', '8', '*', '(', '1', '+', '2', ')'}; int result = evaluate(infixExp, 13); char *suffixExp = infix2Suffix(infixExp, 13); printf("\n"); while(*suffixExp!= '#') printf("%c", *suffixExp++); printf("\n%d", result); return; }
相关文章推荐
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 表达式求值 数据结构 C/C++ 栈的应用
- 栈的应用-四则运算表达式求值
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java) (转载)
- 栈的应用实例---表达式求值(C语言)
- 数据结构习作之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java) (技术含量少许)
- 通过算术表达式求值说明栈的应用
- 表达式求值,栈的应用(C语言)
- 栈的应用 表达式求值
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 栈的应用_表达式求值_C#实现
- C语言 算数表达式求值(顺序栈应用实例)
- 回顾数据结构之栈的应用-表达式求值
- 表达式求值——栈的应用
- 四则运算表达式求值(栈的应用)
- 表达式求值(栈的应用)(C++)
- 栈的经典应用之一——表达式求值
- 栈的应用举例:数制转换,表达式求值
- 栈应用——表达式求值
- NYOJ 题目35 表达式求值 (栈的应用)前中后缀,