栈的应用:解析算术表达式
2016-10-04 09:36
330 查看
原博客:http://blog.csdn.net/zhangxiangDavaid/article/details/27176751
类似于 1*2-3+4-(5-6)-2/4 的式子,我们称为算术表达式。下面我们利用栈这种数据结构来解析它,即用栈来辅助计算算术表达式。
首先我们得明确计算规则:
先左后右:从左算到右
先乘除,后加减
先括号内,后括号外
原理:
使用两个栈来存储读入的字符:数字栈和符号栈
读入数字,则压入数字栈
读入符号,则把当前符号栈顶的符号与读入的符号进行优先级比较。若当前符号栈顶符号的优先级小,则继续把符号压入符号栈;若当前读入符号的优先级小,则数字栈依次出栈两个数,加上符号栈顶的符号,构成一算术表达式,通过计算得出结果,把结果压入数字栈。
当读入界限符或符号栈弹出界限符,如#,运算结束,数字栈弹栈,即最后的表达式值。
难点:
1、优先级数组priority的理解是难点。
+ - * / ( ) #
+ 1 1 2 2 2 1 1
- 1 1 2 2 2 1 1
* 1 1 1 1 2 1 1
/ 1 1 1 1 2 1 1
( 2 2 2 2 2 3 0
) 1 1 1 1 0 1 1
#2 2 2 2 2 0 3
每一个位置可以用(i,j)表示,其中i是行,j是列。有一点要明确:符号i是先于符号j的。也就是说,在算术表达式中符号i位于符号j的左边。1:>,2:<,3:=。界限符#的优先级是最低的。举几个例子说明:
(+,+)=1,两个’+’是同级的,但第一个先于第二个,由上述的计算规则1知:>。
((,#)=0,如果左括号’(‘出现了,至少右括号’)’出现了之后,才会有界限符,否则出错。
(),()=0,我们不支持(…)(…)这种写法,两括号之间至少要有其它的操作符才行,如(…)*(…)。
(#,))=0,没遇到左括号’(‘,怎能出现右括号’)’,故出错。
2、当符号栈顶的符号优先级高于当前读入的操作符时,数字栈出栈的第一个数字作为第二个操作数,下一个出栈的数字才作为第一个操作数,这一点得明白。operand:操作数 operator:操作符
细节看代码:
说明:可以使用栈的实现:顺序栈中的代码,但这里为了方便,减少代码量,使用#include,其实效果是一样的。以上程序,只是完成了简单的运算。说它简单是因为:只能输入0-9的数字,并且不能处理以符号开头的表达式,如-3*4,+2-5,则出错。后续补充增强版,能处理诸如 34+34,多位数的运算。
update 2014-5-28 00:28
这次更新,解决了上述问题,并添加了求余%运算符。代码如下:
类似于 1*2-3+4-(5-6)-2/4 的式子,我们称为算术表达式。下面我们利用栈这种数据结构来解析它,即用栈来辅助计算算术表达式。
首先我们得明确计算规则:
先左后右:从左算到右
先乘除,后加减
先括号内,后括号外
原理:
使用两个栈来存储读入的字符:数字栈和符号栈
读入数字,则压入数字栈
读入符号,则把当前符号栈顶的符号与读入的符号进行优先级比较。若当前符号栈顶符号的优先级小,则继续把符号压入符号栈;若当前读入符号的优先级小,则数字栈依次出栈两个数,加上符号栈顶的符号,构成一算术表达式,通过计算得出结果,把结果压入数字栈。
当读入界限符或符号栈弹出界限符,如#,运算结束,数字栈弹栈,即最后的表达式值。
难点:
1、优先级数组priority的理解是难点。
+ - * / ( ) #
+ 1 1 2 2 2 1 1
- 1 1 2 2 2 1 1
* 1 1 1 1 2 1 1
/ 1 1 1 1 2 1 1
( 2 2 2 2 2 3 0
) 1 1 1 1 0 1 1
#2 2 2 2 2 0 3
每一个位置可以用(i,j)表示,其中i是行,j是列。有一点要明确:符号i是先于符号j的。也就是说,在算术表达式中符号i位于符号j的左边。1:>,2:<,3:=。界限符#的优先级是最低的。举几个例子说明:
(+,+)=1,两个’+’是同级的,但第一个先于第二个,由上述的计算规则1知:>。
((,#)=0,如果左括号’(‘出现了,至少右括号’)’出现了之后,才会有界限符,否则出错。
(),()=0,我们不支持(…)(…)这种写法,两括号之间至少要有其它的操作符才行,如(…)*(…)。
(#,))=0,没遇到左括号’(‘,怎能出现右括号’)’,故出错。
2、当符号栈顶的符号优先级高于当前读入的操作符时,数字栈出栈的第一个数字作为第二个操作数,下一个出栈的数字才作为第一个操作数,这一点得明白。operand:操作数 operator:操作符
细节看代码:
#include<iostream> #include<stack> using namespace std; char OP[7] = {'+','-','*','/','(',')','#'}; //运算符集合 int priority[7][7] = //各运算符相遇时,优先级比较 1:大于,2:小于,3:等于,0:不可能,错误 { { 1, 1, 2, 2, 2, 1, 1 }, { 1, 1, 2, 2, 2, 1, 1 }, { 1, 1, 1, 1, 2, 1, 1 }, { 1, 1, 1, 1, 2, 1, 1 }, { 2, 2, 2, 2, 2, 3, 0 }, { 1, 1, 1, 1, 0, 1, 1 }, { 2, 2, 2, 2, 2, 0, 3 } }; bool isOpat(char c) //是否是OP[]中的操作符 { for (int i = 0; i < 7; i++) { if (c == OP[i]) return true; } return false; } int getPriority(char c1,char c2) //比较优先级 { int i, j; for (int r = 0; r < 7; r++) { if (c1 == OP[r]) i = r; if (c2 == OP[r]) j = r; } return priority[i][j]; } int compute(char a, char op, char b) { switch (op) { case '+': return (a - '0') + (b - '0'); case '-': return (a - '0') - (b - '0'); case '*': return (a - '0')*( b - '0'); case '/': if (b == '0') { cout << "错误!" << endl; exit(0); } return (a - '0')/(b - '0'); } } void evaluateExpression() //计算 { stack<char> opan,opat; //构建两个栈 operand:操作数,operator:操作符 opat.push('#'); // # 压入符号栈,作为界限符 cout << "输入算术表达式" << endl; char op,a,b,c; c=getchar(); while (c != '#' || opat.top() != '#') //没有读到 '#',或者符号栈也没空,则继续读取字符 { //对读入的字符进行判断:是操作数还是操作符? if (!isOpat(c)) //是操作数则压入操作数栈 { opan.push(c); c = getchar(); } else //若是操作符,则需把符号栈顶的操作符与当前读入的操作符,进行优先级比较 { switch(getPriority(opat.top(), c)) { case 1: op = opat.top(); opat.pop(); b = opan.top(); opan.pop(); a = opan.top(); opan.pop(); opan.push(char(compute(a,op,b)+'0')); break; case 2: opat.push(c); c = getchar(); break; case 3: opat.pop(); c = getchar(); break; case 0: cout << "错误!" << endl; exit(0); } } } cout << "= " << opan.top()-'0' << endl; } int main() { cout << "使用栈结构解析计算表达式"<<endl; evaluateExpression(); system("pause"); return 0; }
说明:可以使用栈的实现:顺序栈中的代码,但这里为了方便,减少代码量,使用#include,其实效果是一样的。以上程序,只是完成了简单的运算。说它简单是因为:只能输入0-9的数字,并且不能处理以符号开头的表达式,如-3*4,+2-5,则出错。后续补充增强版,能处理诸如 34+34,多位数的运算。
update 2014-5-28 00:28
这次更新,解决了上述问题,并添加了求余%运算符。代码如下:
#include<iostream> #include<stack> using namespace std; char OP[8] = {'+','-','*','/','%','(',')','#'}; //运算符集合 int priority[8][8] = //各运算符相遇时,优先级比较 1:大于,2:小于,3:等于,0:不可能,错误 { { 1, 1, 2, 2, 2, 2, 1, 1 }, { 1, 1, 2, 2, 2, 2, 1, 1 }, { 1, 1, 1, 1, 1, 2, 1, 1 }, { 1, 1, 1, 1, 1, 2, 1, 1 }, { 1, 1, 1, 1, 1, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 3, 0 }, { 1, 1, 1, 1, 1, 0, 1, 1 }, { 2, 2, 2, 2, 2, 2, 0, 3 } }; bool isOpat(char c) //是否是OP[]中的操作符 { for (int i = 0; i < 8; i++) { if (c == OP[i]) return true; } return false; } int getPriority(char c1,char c2) //比较优先级 { int i, j; for (int r = 0; r < 8; r++) { if (c1 == OP[r]) i = r; if (c2 == OP[r]) j = r; } return priority[i][j]; } int compute(int a, char op, int b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a*b; case '/': case '%': if (b == 0) { cout << "错误!" << endl; exit(0); } if (op == '/') return a / b; else return a%b; } } void evaluateExpression() //计算 { stack<int> opan; //操作数栈 stack<char> opat; //操作符栈 opat.push('#'); // # 压入符号栈,作为界限符 cout << "输入算术表达式" << endl; char op,c,cn; //cn:char next下一个字符 int a,b,data; c=getchar(); if (isOpat(c)) //如果第一个字符就是操作符,则把0压入数字栈 opan.push(0); while (c != '#' || opat.top() != '#') //没有读到 '#',或者符号栈也没空,则继续读取字符 { //对读入的字符进行判断:是操作数还是操作符? if (!isOpat(c)) //是操作数则压入操作数栈 { data = c - '0'; while (!isOpat(cn = getchar())) //下一个字符任为数字 { data = data * 10 + cn - '0'; } opan.push(data); c = cn; //把cn中的操作符赋给c } else //若是操作符,则需把符号栈顶的操作符与当前读入的操作符,进行优先级比较 { switch(getPriority(opat.top(), c)) { case 1: op = opat.top(); opat.pop(); b = opan.top(); opan.pop(); a = opan.top(); opan.pop(); opan.push(compute(a,op,b)); break; case 2: opat.push(c); c = getchar(); break; case 3: opat.pop(); c = getchar(); break; case 0: cout << "错误!" << endl; exit(0); } } } cout << "= " << opan.top() << endl; } int main() { cout << "使用栈结构解析计算表达式"<<endl; evaluateExpression(); system("pause"); return 0; }
相关文章推荐
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 数据结构之应用"栈(Stack)"实现: 解析算术表达式及计算
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 栈的应用:解析算术表达式
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 数据结构习作之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java) (技术含量少许)
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java) (转载)
- C++二叉树应用:计算算术表达式
- 堆栈解析算术表达式
- 数据结构之应用"栈(Stack)"实现: 解析算术表达式及计算
- 算术表达式解析(第二版) C++11版
- 堆栈的应用(2) 中缀算术表达式到后缀(逆波兰记法reverse polish notation)的转换及其计算 C++实现
- 堆栈的应用(2) 中缀算术表达式到后缀(逆波兰记法reverse polish notation)的转换及其计算 C++实现
- JAVA数据结构学习实例--利用栈解析算术表达式
- 栈的应用(解析表达式并计算)
- 实验一 线性表及其应用 算术表达式求值
- 用栈解析算术表达式[Python版]
- 后缀表达式与解析算术表达式
- 栈的应用 算术表达式的计算