要解决的问题
任何一个表达式都是由操作数(operand),运算符(operator),和界限符(delimiter)组成的,求表达式主要的问题有:
1:表达式是否合理;
2;符号的优先级关系;
3;多位数处理
4;正确求值;
1.算法基本思想描述:
处理该题型,我运用了栈的知识,首先初建OPTR(运算符)和OPND(数字)两个栈,后输入字符串以‘=’结束,对每个字符进行分析,若ch为数字,则压入OPND栈,若ch为运算符号,先判断OPTR栈头和ch的优先级关系,再做不同的处理,数据处理后,OPND栈顶元素就是表达式求值结果,返回元素。
2.算法的设计
(1)判断表达式是否合理
输入字符串时,要判断该字符串的正确性;
像1+3+4+6+123=
1*3*4/4+(1+5=
1+(2*3)+4*5*6/6=
以上三个都为正确表达式结果会给出相应的值
1.若出现:其他符号如‘?’,‘、’,‘&’等等都是错误符号,扫描时会给出相应的错误信息提示。
2.若出现表达式输入错误,如:
1++2++3=
1(2+3)=
等错误,也会给出相应的错误提示。
3.出现括号不匹配现象如
()1+2)=3;
也会给出相应的现象。
(2)符号的优先级关系!
算数四则运算遵循以下三条规则:
1.先乘除后加减;
2.从左往右运算;
3.先括号内,后括号外;
根据以上规则,在运算每一步中,任意两个相继出现的运算符O1和O2之间的关系至多是下面三种:
O1<O2; O1的优先权低
O1=O2; 两优先权相等
O1>O2; O1的优先权高
则有表格
O1 O2 | + | - | * | / | ( | ) | = |
+ | > | > | < | < | < | > | > |
- | > | > | < | < | < | > | > |
* | > | > | > | > | < | > | > |
/ | > | > | > | > | < | > | > |
( | < | < | < | < | < | = | |
) | > | > | > | > | > | > | |
= | < | < | < | < | < | = |
根据规则1,2,3,可以得出此表格。
例如:当O2=‘+’, ‘-’时,O1为‘(’,‘=’时,优先级小于O2,其他时优先级大于O2.
表格中有出现‘=’为括号匹配,当‘(’和‘)’碰见时,消除括号,括号内运算先完成,为了方便程序运行,在开头时符号栈(OPTR)入栈‘=’,结尾符号栈(OPTR)入栈‘=’是为了让‘=’=‘=’匹配完成终止程序。
使用两个工作栈 OPTR(寄存运算符),
OPND(寄存操作数或运算结果)。
一.初始化OPTR栈和OPND栈,将‘=’压入OPTR栈。
二.扫描表达式,读入第一个字符(我的方法是字符ch一个一个输入),如果表达式没有扫描至‘=’或OPRT栈顶元素不为‘=’则循环以下操作:
若ch是操作数,则压入OPND栈,读下一个字符ch。
若ch是运算符,则比较OPTR的栈顶元素和ch的优先级,有三种情况分别对应三个不同的处理方法。
1.若是小于,则ch压入OPTR栈,读入下一个字符;
2.若是大于,则弹出OPTR栈顶的运算符,弹出OPND栈的两个数,进行相应运算,结果压入OPND栈;
3.若是等于(等于的情况有括号匹配),弹出栈顶的‘(’,读入下一个字符;
三.数据处理后,OPND栈顶元素就是表达式求值结果,返回元素。
(3)多位数处理:
扫描ch为操作数时,ch只能一个一个入栈,则出现多位数入123时,它会一个一个入栈,则得不到123这个数,为了解决这个方法,在操作数入栈前对该操作数进行分析,其中用到判断数flag=1和保存数q(q初始化为0).
输入一个操作数时,先将他保存在q中,并且处理:
q*10+ch; flag=1;
输入下一个字符ch
直到ch为符号数时:if(In(ch)) //In(ch)函数判断ch是否是运算符。
if(flag==1)
将q的值入OPND栈,
q=0;
flag=1;
如处理123这个数字,读入1后,q=1,读入2后q=1*10+2=12,读入3时,q=12*10+3=123,后读入运算符如+时,进入运算符处理,则此时flag=1,将q的值入OPND栈,后把还原q=0和flag=0,再读下一个字符ch。
源代码主要函数如下:
//栈的初始化
typedef struct
{
double *base;
double *top;
double stacksize;
} SqStack;
double InitStack( SqStack &S ) //创建一个空栈
{
S.base=new double[MAXSIZE];
if(!S.base)
exit(OVERFLOW);
S.top=S.base;
S.stacksize=MAXSIZE;
return OK;
}
//1.主函数.Calculate();
GetTop(SqStack &S) //返回栈头值。
StackEmpty( SqStack S ) //判空
Pop( SqStack &S, double &e) //入栈。
Push( SqStack &S, double e) //出栈。
InitStack( SqStack &S ) //建立一个空栈;
In(int c) //判断c是否为运算符。
Precede(char t1,char t2) //判断两个运算符的优先关系
Operate(double a,int theta,double b) //对两个数进行二元运算
judge_rationality (ch[ ]) //判断字符串输入是否合理
Match(ch[ ]) //判断是否括号配对
代码运行过程如下:
如处理数据1+(20+4)/(4-1)
正确的结果为9
则其中的处理过程如下表格
初始建立两个两个空栈 OPTR和OPND;
步骤 | OPTR栈 | OPND栈 | 读入字符 | 主要操作 |
1 | = | 1+(20+4)/(4-1)= | Push(OPND, 1) | |
2 | = | 1 | +(20+4)/(4-1)= | Push(OPTR,‘+’) |
3 | =+ | 1 | (20+4)/(4-1)= | Push(OPTR,‘(’) |
4 | =+( | 1 | 20+4)/(4-1)= | Push(OPND, 20) |
5 | =+( | 1 20 | +4)/(4-1)= | Push(OPTR,‘+’) |
6 | =+(+ | 1 20 | 4)/(4-1)= | Push(OPND, 4 ) |
7 | =+(+ | 1 20 4 | )/(4-1)= | Push(OPND,Operate |
8 | =+( | 1 24 | )/(4-1)= | Pop(OPTR) |
9 | =+ | 1 24 | /(4-1)= | Push(OPTR,‘/’) |
10 | =+/ | 1 24 | (4-1)= | Push(OPTR,‘(’) |
11 | =+/( | 1 24 | 4-1)= | Push(OPND,4) |
12 | =+/( | 1 24 4 | -1)= | Push(OPTR,‘-’) |
13 | =+/(- | 1 24 4 | 1)= | Push(OPND,1) |
14 | =+/(- | 1 24 4 1 | )= | Push(OPND,Operate |
15 | =+/( | 1 24 3 | )= | Pop(OPTR) |
16 | =+/ | 1 24 3 | = | Push(OPND,Operate |
17 | =+ | 1 8 | = | Push(OPND,Operate |
18 | = | 9 | = | return(GetTop(OPND) |
- 源程序清单:
#include <bits/stdc++.h>
#include<string.h>
using namespace std;
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef struct
{
double *base;
double *top;
double stacksize;
} SqStack;
double InitStack( SqStack &S ) //创建一个空栈
{
S.base=new double[MAXSIZE];
if(!S.base)
exit(OVERFLOW);
S.top=S.base;
S.stacksize=MAXSIZE;
return OK;
}
int StackEmpty( SqStack S ) //判空
{
if(S.top==S.base)
return OK;
return ERROR;
}
double Push( SqStack &S, double e) //入栈
{
if(S.top-S.base==S.stacksize)
return ERROR;
*S.top++=e;
return OK;
}
double Pop( SqStack &S, double &e) //出栈
{
if(S.top==S.base)
return ERROR;
e=*--S.top;
return OK;
}
double GetTop(SqStack &S) //返回栈头值
{
return *(S.top-1);
}
int In(int c) // 判断c是否为运算符
{
switch(c)
{
case'+':
return TRUE;
break;
case'-':
return TRUE;
break;
case'*':
return TRUE;
break;
case'/':
return TRUE;
break;
case'(':
return TRUE;
break;
case')':
return TRUE;
break;
case'=':
return TRUE;
default:
return FALSE;
}
}
char Precede(char t1,char t2) //判断两个运算符的优先关系
{
char f;
switch(t2)
{
case '+':
case '-':
if(t1=='('||t1=='=')
f='<';
else
f='>';
break;
case '*':
case '/':
if(t1=='+'||t1=='-'||t1=='('||t1=='=')
f='<';
else
f='>';
break;
case '(':
if(t1==')')
break;
else
f='<';
break;
case ')':
if(t1=='(')
f='=';
else if(t1=='=')
break;
else
f='>';
break;
case '=':
if(t1=='=')
f='=';
else if(t1=='(')
{
break;
}
else
f='>';
break;
default:
break;
}
return f;
}
double Operate(double a,int theta,double b) //对a和b进行二元运算theta
{
double c;
switch(theta)
{
case'+':
c=a+b;
break;
case'-':
c=a-b;
break;
case'*':
c=a*b;
break;
case'/':
c=(double)a/b;
break;
default:
break;
}
return c;
}
int judge_rationality(char str[]) //判断表达式是否合理
{
int len=strlen(str);
if(str[0]=='/'||str[0]=='*')
return 0;
if(str[len-1]<'0'&&str[len-1]>'9')
return 0;
for(int i=0; i<len; i++)
{
if(str[i]=='(')
{
if(i==0&&(str[i+1]=='*'||str[i+1]=='/')||str[i+1]=='=')
return 0;
if(str[i+1]==')')
return 0;
if(str[i-1]>='0'&&str[i-1]<='9')
return 0;
}
if(str[i]==')')
{
if(i==0)
return 0;
if(str[i-1]=='+'||str[i-1]=='*'||str[i-1]=='-'||str[i-1]=='/')
return 0;
if(str[i+1]>='0'&&str[i+1]<='9')
return 0;
if(str[i+1]>='0'&&str[i+1]<='9'&&i<len-1)
return 0;
}
if((str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'))
{
if(str[i+1]=='+'||str[i+1]=='-'||str[i+1]=='*'||str[i+1]=='/')
return 0;
}
if(str[i]=='/')
{
if(str[i+1]=='0')
{
cout<<"分母不能为 0"<<endl;
return 0;
}
}
}
return 1;
}
int Match(char str[]) //判断括号是否匹配
{
SqStack S;
InitStack(S);
double e;
double x=-1;
int len=strlen(str);
for(int i=0; i<len; i++)
{
char ch=str[i];
switch (ch)
{
case '(':
Push(S,x);
break;
case ')':
if(Pop(S,e)==0)
{
return 0;
}
break;
}
}
int k=StackEmpty(S);
if(k==1)
{
return 1;
}
else
{
return 0;
}
}
void Calculate()
{
SqStack OPND; //定义操作数栈
SqStack OPTR; //定义符号栈
InitStack(OPND); //开空间
InitStack(OPTR);
double theta,a,b,x; //用户函数Operate(a,theta,b);
double q=0; //记录多值;
int flag=1; // 判断多值数是否入栈;
int flag2=1; // 判断栈头值是否输出;
int i=0,len; //len为字符串长度
int k2=0; //返回Check(ch)的值
int k=0; //返回judge_infix(ch)的值
char ch2; //输入字符;
char ch[MAXSIZE]; //定义数组 保存算术表达式
Push(OPTR,'='); //开始时将'='进OPTR栈;
cin>>ch; //输入字符串
ch2=ch[0];
len=strlen(ch);
k2=Match(ch); //括号是否匹配;
if(k2==0)
{
cout<<"输入错误!"<<endl;
return;
}
if(k2==1)
{
k=judge_rationality(ch);
if(k==0)
cout<<"输入错误!"<<endl;
if(k==1)
{
while(ch2!='='||GetTop(OPTR)!='=')
{
if(ch2>='0'&&ch2<='9')
{
ch2-='0'; //ASCLL表互换;
q=q*10+ch2; //多值保存
if(len<3&&ch[len-1]=='=')
{
cout<<q<<endl;
return;
}
flag=1; //判断多值是否入栈
i++;
ch2=ch[i]; //提取下一个字符
}
else if(In(ch2)) // 若ch2为运算符
{
if(flag==1) //若flag=1 则将多值数入栈;
{
Push(OPND,q);
q=0;
flag=0;
}
switch(Precede(GetTop(OPTR),ch2)) //比较OPTR栈顶元素和ch的优先级
{
case'<': //当前字符压入OPTR栈,读下一个字符
Push(OPTR,ch2);
i++;
ch2=ch[i]; //提取下一个字符
break;
case '>': //弹出OPTR栈顶运算符,同时弹出OPND栈顶的两个数
Pop(OPTR,theta); //运算符出栈
Pop(OPND,b); //b出栈
Pop(OPND,a); //a出栈
Push(OPND,Operate(a,theta,b)); //将运算结果压入OPND栈
break;
case '=': //OPTR栈顶元素并且x='(', ch=')'
Pop(OPTR,x); //弹出OPTR的栈顶元素'(';
i++;
ch2=ch[i]; //提取下一个字符
break;
}
}
else
{
cout<<"输入错误!"<<endl;
getchar();
return;
}
}
cout<<fixed<<setprecision(2)<<GetTop(OPND)<<endl;
}
}
}
int main()
{
double x;
int n=0;
cout<<"-------------------算术表--------------------"<<endl;
cout<<"*********************************************"<<endl;
for(int i=0;; i++)
{
if(n==-1)
break;
cout<<"请输入算术表达式,并以 = 结束."<<endl;
Calculate();
cout<<"若输入(-1)则退出程序,输入其他数字则程序继续进行!请选择:"<<endl;
cin>>n;
cout<<" " <<endl;
}
return 0;
}
- 测试数据及测试结果:
以上就是数据结构—算术表达式的实现过程!希望对你们有所帮助!