1.内容和要求
任务:
编程序实现堆栈,并且使用堆栈实现常用算术表达式求解
要求:
1.实现堆栈,包括堆栈的初始化,push和pop操作;
2.输入表达式,使用堆栈实现表达式求解算术结果,输出答案。
测试:2-4*(4-6/3)+3*2
2.解决方案和关键代码
2.1 解决方案
表达式求值可以看成是由操作数和算符(运算符和界限符)组成的。算术的四则运算的规则:①先乘除,后加减;②从左算到右;③先括号内,后括号外。我们可以根据这个运算的优先关系的规定来实现对表达式的求值。
为实现算符优先算法,可以使用两个工作栈。一个称作OPTR,用以寄存运算符,另一个称作OPND,用以寄存操作数和运算结果。算法的基本思想是:
2.2 关键代码
float evaluation(){
StackChar OPTR;
StackFloat OPND;
char TempData[20],Dr[2];
char theta,c,x;
float a,b,Data;
InitStack(OPTR);
Push(OPTR,'#');
InitStack(OPND);
c = getchar();
while(c!='#' || GetTop(OPTR) != '#'){
if(!In(c)){
//不是算术运算符
Dr[0] = c;
Dr[1] = '\0';
strcat(TempData,Dr);
c = getchar();
if(In(c)){
Data = (float)atof(TempData);
Push(OPND,Data);
strcpy(TempData,"\0");
}
}
else{
switch(Precede(GetTop(OPTR),c)){
case '<':
Push(OPTR,c);
c = getchar();
break;
case '=':
Pop(OPTR,x);
c = getchar();
break;
case '>':
Pop(OPTR,theta);
Pop(OPND,b);
Pop(OPND,a);
Push(OPND,operate(a,theta,b));
break;
}
}
}
return GetTop(OPND);
}
3.总结与改进
3.1总结
表达式求值主要集中在算符的优先级如何处理的问题,将操作数和运算符的进出栈加以转化。但在进栈的时候不得不要面临数据类型强制转换的问题。本文采用字符数组,getchar()读入字符后加以判断,当不是运算符时,为增强程序的鲁棒性,还需要再getchar(),每次将操作字符暂时存储在字符数组Dr[1]中,Dr[0]赋值‘/0’,即Dr变成字符数组,Dr再通过strcat函数追加到TempData[20]中,直到再次读取到运算符才把之前的TempData入栈。而strcpy(TempData,”\0”)将TempData初始化。
3.2改进
本文分别定义了操作数栈和运算符栈,但操作略微繁琐。可将操作数栈和运算符栈合并为同一个栈,通过字符类型进行统一处理,在进出栈时再进行强制类型转换,但是本文为了使得思路更加清晰,暂不使用同一个栈,把问题的焦点集中在操作数和运算符的进出栈选择的操作问题。两者皆有优点。
附录
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
#define STACKSIZE 100
//运算符集合
char OPSET[7]={'+' , '-' , '*' , '/' ,'(' , ')' , '#'};
//运算符间的优先关系
char Prior[7][7] = {
'>','>','<','<','<','>','>',
'>','>','<','<','<','>','>',
'>','>','>','>','<','>','>',
'>','>','>','>','<','>','>',
'<','<','<','<','<','=',' ',
'>','>','>','>',' ','>','>',
'<','<','<','<','<',' ','='
};
//运算符栈
typedef struct{
char *base;
char *top;
int stacksize;
}StackChar;
//操作数栈
typedef struct{
float *base;
float *top;
int stacksize;
}StackFloat;
void InitStack(StackChar &S){
//运算符栈初始化
S.base = new char[STACKSIZE];
if(!S.base)
return;
S.top = S.base;
S.stacksize = STACKSIZE;
}
void InitStack(StackFloat &S){
//操作数栈初始化
S.base = new float[STACKSIZE];
if(!S.base)
return;
S.top =S.base;
S.stacksize = STACKSIZE;
}
void Push(StackChar &S,char e){
//运算符压栈
if(S.top-S.base==S.stacksize)
return;
*S.top++ = e;
}
void Push(StackFloat &S,float e){
//操作数压栈
if(S.top-S.base==S.stacksize)
return;
*S.top++ = e;
}
void Pop(StackChar &S,char &e){
//运算符出栈
if(S.top == S.base) exit(-1);
e = *--S.top;
}
void Pop(StackFloat &S,float &e){
//运算符出栈
if(S.top == S.base) exit(-1);
e = *--S.top;
}
char GetTop(StackChar S){
//运算符栈顶元素
return *(S.top-1);
}
float GetTop(StackFloat S){
//运算符栈顶元素
return *(S.top-1);
}
bool In(char c){
//判断是否为运算符
for(int i=0; i<7; i++){
if(c==OPSET[i])
return true;
}
return false;
}
int Position(char c){
//表中的位置
for(int i=0; i<7; i++){
if(c == OPSET[i])
return i;
}
return 0;
}
char Precede(char c1,char c2){
//表中的优先关系
return Prior[Position(c1)][Position(c2)];
}
float operate(float a,char theta,float b){
float result;
switch(theta){
case '+':
result = a+b;
break;
case '-':
result = a-b;
break;
case '*':
result = a*b;
break;
case '/':
result = a/b;
break;
default:
result = 0;
}
return result;
}
float evaluation(){
StackChar OPTR;
StackFloat OPND;
char TempData[20],Dr[2];
char theta,c,x;
float a,b,Data;
InitStack(OPTR);
Push(OPTR,'#');
InitStack(OPND);
c = getchar();
while(c!='#' || GetTop(OPTR) != '#'){
if(!In(c)){
//不是算术运算符
Dr[0] = c;
Dr[1] = '\0';
strcat(TempData,Dr);
c = getchar();
if(In(c)){
Data = (float)atof(TempData);
Push(OPND,Data);
strcpy(TempData,"\0");
}
}
else{
switch(Precede(GetTop(OPTR),c)){
case '<':
Push(OPTR,c);
c = getchar();
break;
case '=':
Pop(OPTR,x);
c = getchar();
break;
case '>':
Pop(OPTR,theta);
Pop(OPND,b);
Pop(OPND,a);
Push(OPND,operate(a,theta,b));
break;
}
}
}
return GetTop(OPND);
}
int main(){
cout<<"表达式(#号结束输入)"<<endl;
float a;
a = evaluation();
cout<<"结果是"<<endl;
cout<<a<<endl;
return 0;
}
本文的实现思路来自教材53页;
本程序的数据类型转换思路来自以此博客: