題目:設(shè)計一個程序结蟋,演示用算符優(yōu)先法對算數(shù)表達式求值的過程。
一迫摔、需求分析
以字符序列的形式從終端讀入輸入語法正確轴踱、不含變量的整數(shù)表達式埃元。利用教科書表3.1給出的算符優(yōu)先關(guān)系涝涤,實現(xiàn)對算數(shù)四則混合運算表達式的求值,并仿照教科書的例子3-1演示在求值中運算符棧岛杀、運算數(shù)棧阔拳、輸入字符和主要操作的變化過程。
2.測試數(shù)據(jù)
(1)3*(7-2);
(2)8;1+2+3+4;88-1*5;1024/4*8;1024/(4*8);(20+2)/(6/2);
(3)3-3-3;8/(9-9);2*(6+2*(3+6*(6+6)));(((6+6)*(6+3)*2+6)*2;
二类嗤、概要設(shè)計
1. 數(shù)據(jù)結(jié)構(gòu)
主要數(shù)據(jù)類型為:
ADT Stack{
數(shù)據(jù)對象:
D={ai|a∈EleSet,i=1,2,...,n,n≥0}
數(shù)據(jù)關(guān)系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,...,n}
約定an為棧頂糊肠,a1為棧底。
基本操作:
InitStack(&S)
操作結(jié)果:構(gòu)造一個空棧S
GetTop(S, &e)
初始條件:棧S已存在且非空
操作結(jié)果:用e返回S棧頂元素
Pop(&S, &e)
初始條件:棧S已存在
操作結(jié)果:刪除S的棧頂元素遗锣,并用e返回其值
Push(&S, e)
初始條件:棧S已存在
操作結(jié)果:插入e為新的棧頂元素
}
2. 使用函數(shù)
int InitTRStack(TRStack *S)
int InitNDStack(NDStack *S)
操作結(jié)果:構(gòu)造運算符棧和操作數(shù)棧
char TRGetTop(TRStack *S)
float NDGetTop(NDStack *S)
操作結(jié)果:返回運算符棧和操作數(shù)棧的棧頂元素
int TRPush(TRStack *S, char e)
int NDPush(NDStack *S, float e)
操作結(jié)果:插入棧頂元素
int TRPop(TRStack *S, char *e)
int NDPop(NDStack *S, float *e)
操作結(jié)果:刪除棧頂元素货裹,返回其值
float Opreate(float a, float b, char theta)
操作結(jié)果:對操作數(shù)和對應(yīng)的運算符進行計算返回結(jié)果
int In(char c,char *OP)
操作結(jié)果:判定字符是否為運算符
char Precede(char m, char n, char *OP)
操作結(jié)果:判斷運算符的優(yōu)先級
int OutPutNDStack(NDStack *S)
int OutPutTRStack(TRStack *S)
操作結(jié)果:輸出運算符和操作數(shù)棧內(nèi)所有元素
三、詳細設(shè)計
1. 數(shù)據(jù)儲存結(jié)構(gòu)
運算符棧采用char類型棧黄伊,操作數(shù)棧采用float類型棧
OPND和OPTR棧的實現(xiàn)如下:
typedef struct {
char *base;
char *top;
int stacksize;
}TRStack;
typedef struct {
float *base;
float *top;
int stacksize;
}NDStack;
2. 計算功能實現(xiàn)
為實現(xiàn)算符優(yōu)先級算法泪酱,使用兩個工作棧,一個稱作OPTR还最,用以寄存運算符墓阀,一個稱作OPND,用以寄存操作爍或運算結(jié)果拓轻。算法的基本思想為:
(1)首先置操作數(shù)棧為空棧斯撮,表達式起始符“#”為運算符棧的棧底元素;
(2)依次讀入表達式中的每個字符扶叉,若是操作數(shù)則進OPND棧勿锅,若是運算符則和OPTR棧的棧頂運算符比較有限權(quán)后做相應(yīng)操作,直到OPTR棧的棧頂元素和當前讀入字符均為“#”
float EvaluateExpression(char *expr){
// 算數(shù)表達式求值的算符優(yōu)先算法枣氧。OPTR和OPND分別為運算符棧和運算數(shù)棧
// OP為運算數(shù)的集合
char OP[8] = {'+','-','*','/','(',')','#','\0'};
TRStack OPTR; NDStack OPND;
char *c;
char End[] = {'#','\0'};
char cc[254];
float a,b;
char theta,x;
float cf;
InitTRStack(&OPTR); TRPush(&OPTR,'#');
InitNDStack(&OPND); c = strcat(expr,End); // 拼接表達式使其以#結(jié)尾
while(*c!='#' || TRGetTop(&OPTR)!='#') {
if(!In(*c,OP)){
while(!In(*c,OP)){strcat(cc,c);c++;} // 兩位數(shù)以上數(shù)字輸入
cf = atof(cc);
OutPutTRStack(&OPTR);
OutPutNDStack(&OPND);
printf("輸入字符:%f ",cf);
memset(cc, 0x00, sizeof (char) * 256); // 清空臨時字符串
NDPush(&OPND,cf);
printf("操作:Push(OPND,%f)\n",cf);
} // 不是運算符進棧
else{
OutPutTRStack(&OPTR);
OutPutNDStack(&OPND);
printf("輸入字符:%c ",*c);
switch(Precede(TRGetTop(&OPTR),*c,OP)){
case'<': // 棧頂元素優(yōu)先權(quán)低
TRPush(&OPTR,*c);
printf("操作:Push(OPTR,%c)\n",*c);
c++;
break;
case'=': // 脫括號指針移動到下一字符
TRPop(&OPTR,&x);
printf("操作:Pop(OPTR,%c)\n",x);
c++;
break;
case'>': // 退棧并將運算結(jié)果入棧
TRPop(&OPTR,&theta);
NDPop(&OPND,&b);
NDPop(&OPND,&a);
NDPush(&OPND,Opreate(a,b,theta));
printf("操作:Opreate(%f,%c,%f)\n",a,theta,b);
break;
}
}
}
OutPutTRStack(&OPTR);
OutPutNDStack(&OPND);
printf("輸入字符:%c ",*c);
printf("操作:return GetTop(OPND)\n");
return NDGetTop(&OPND);
}
4. 主程序
通過判斷讀入表達式中元素是否僅為數(shù)字和符號以及左右括號數(shù)目是否相等來決定是否進行下一步計算
int main(){
// cnt1,cnt2 記錄左右括號個數(shù)
// falg 標志輸入是否合法
char Exp[254];
int i = 0;
int cnt1 = 0;
int cnt2 = 0;
int flag = 0;
printf("input equation:\n");
gets(Exp);
char stdinput[17] = {'+','-','*','/','(',')','1','2','3','4','5','6','7','8','9','0','\0'};
while(Exp[i]!='\0'){
if(Exp[i]=='(') cnt1++;
if(Exp[i]==')') cnt2++;
if(!In(Exp[i],stdinput)) {flag = 1; break;}
else i++;
}
if(cnt1!=cnt2) flag = 1;
if(!flag) {printf("結(jié)果:%f",EvaluateExpression(Exp));}
else {printf("invalid input\n");}
}
5. 程序的層次結(jié)構(gòu)
五溢十、用戶手冊
- 本程序的運行環(huán)境為DOS操作系統(tǒng),執(zhí)行文件為:calculation.exe
- 進入程序按提示操作达吞,輸入表達式
- 輸入后按回車符即顯示結(jié)果
六张弛、測試結(jié)果
(1) (((6+6)*6+3)*2+6)*2
七、源代碼
calculation.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<conio.h>
#define STACK_INIT_SIZE 1000
#define STACKNCREMENT 10
typedef struct {
char *base;
char *top;
int stacksize;
}TRStack;
typedef struct {
float *base;
float *top;
int stacksize;
}NDStack;
char TRGetTop(TRStack *S){
char e;
if(S->top == S->base) return 0;
e = *(S->top-1);
return e;
}
float NDGetTop(NDStack *S){
float e;
if(S->top == S->base) return 0;
e = *(S->top-1);
return e;
}
int InitTRStack(TRStack *S){
S->base = (char *)malloc(STACK_INIT_SIZE * sizeof(char));
if(!S->base) exit(-2);
S->top = S->base;
S->stacksize = STACK_INIT_SIZE;
return 1;
}
int InitNDStack(NDStack *S){
S->base = (float *)malloc(STACK_INIT_SIZE * sizeof(float));
if(!S->base) exit(-2);
S->top = S->base;
S->stacksize = STACK_INIT_SIZE;
return 1;
}
int TRPush(TRStack *S, char e){
if(S->top - S->base >= S->stacksize){
S->base = (char *)realloc(S->base, (S->stacksize + STACK_INIT_SIZE * sizeof(char)));
if(!S->base) exit(-2);
S->top = S->base + S->stacksize;
S->stacksize += STACKNCREMENT;
}
*S->top++ = e;
return 1;
}
int NDPush(NDStack *S, float e){
if(S->top - S->base >= S->stacksize){
S->base = (float *)realloc(S->base, (S->stacksize + STACK_INIT_SIZE * sizeof(float)));
if(!S->base) exit(-2);
S->top = S->base + S->stacksize;
S->stacksize += STACKNCREMENT;
}
*S->top++ = e;
return 1;
}
int TRPop(TRStack *S, char *e){
if(S->top == S->base) return 0;
*e = * --S->top;
return 1;
}
int NDPop(NDStack *S, float *e){
if(S->top == S->base) return 0;
*e = * --S->top;
return 1;
}
float Opreate(float a, float b, char theta){
switch(theta){
case'+':return a+b;
case'-':return a-b;
case'/':return a/b;
case'*':return a*b;
default:return 0;
}
}
int In(char c,char *OP){
int flag = 0;
int i = 0;
while(OP[i]!='\0'){
if(OP[i]==c) flag=1;
i++;
}
return flag;
}
char Precede(char m, char n, char *OP){
unsigned char Prior[7][7] =
{'>','>','<','<','<','>','>',
'>','>','<','<','<','>','>',
'>','>','>','>','<','>','>',
'>','>','>','>','<','>','>',
'<','<','<','<','<','=',' ',
'>','>','>','>',' ','>','>',
'<','<','<','<','<',' ','=',};
int i = 0; int j = 0;
while(m != OP[i]) i++;
while(n != OP[j]) j++;
return Prior[i][j];
}
int OutPutNDStack(NDStack *S){
float *c;
c = S->top;
printf("OPND棧: ");
while(c!=S->base){
c--;
printf("%f ",*c);
}
}
int OutPutTRStack(TRStack *S){
char *c;
c = S->top;
printf("OPTR棧: ");
while(c!=S->base){
c--;
printf("%c ",*c);
}
}
float EvaluateExpression(char *expr){
char OP[8] = {'+','-','*','/','(',')','#','\0'};
TRStack OPTR; NDStack OPND;
char *c;
char End[] = {'#','\0'};
char cc[254];
float a,b;
char theta,x;
float cf;
InitTRStack(&OPTR); TRPush(&OPTR,'#');
InitNDStack(&OPND); c = strcat(expr,End);
while(*c!='#' || TRGetTop(&OPTR)!='#') {
if(!In(*c,OP)){
while(!In(*c,OP)){strcat(cc,c);c++;}
cf = atof(cc);
OutPutTRStack(&OPTR);
OutPutNDStack(&OPND);
printf("輸入字符:%f ",cf);
memset(cc, 0x00, sizeof (char) * 256);
NDPush(&OPND,cf);
printf("操作:Push(OPND,%f)\n",cf);
}
else{
OutPutTRStack(&OPTR);
OutPutNDStack(&OPND);
printf("輸入字符:%c ",*c);
switch(Precede(TRGetTop(&OPTR),*c,OP)){
case'<':
TRPush(&OPTR,*c);
printf("操作:Push(OPTR,%c)\n",*c);
c++;
break;
case'=':
TRPop(&OPTR,&x);
printf("操作:Pop(OPTR,%c)\n",x);
c++;
break;
case'>':
TRPop(&OPTR,&theta);
NDPop(&OPND,&b);
NDPop(&OPND,&a);
NDPush(&OPND,Opreate(a,b,theta));
printf("操作:Opreate(%f,%c,%f)\n",a,theta,b);
break;
}
}
}
OutPutTRStack(&OPTR);
OutPutNDStack(&OPND);
printf("輸入字符:%c ",*c);
printf("操作:return GetTop(OPND)\n");
return NDGetTop(&OPND);
}
int main(){
char Exp[254];
int i = 0;
int cnt1 = 0;
int cnt2 = 0;
int flag = 0;
printf("input equation:\n");
gets(Exp);
char stdinput[17] = {'+','-','*','/','(',')','1','2','3','4','5','6','7','8','9','0','\0'};
while(Exp[i]!='\0'){
if(Exp[i]=='(') cnt1++;
if(Exp[i]==')') cnt2++;
if(!In(Exp[i],stdinput)) {flag = 1; break;}
else i++;
}
if(cnt1!=cnt2) flag = 1;
if(!flag) {printf("結(jié)果:%f",EvaluateExpression(Exp));}
else {printf("invalid input\n");}
}