要求说明:
(1)从键盘接收算术表达式,以“#”表示接收结束;
(2)输出算术表达式的值;
(3)操作数仅限于非负整数,操作符只能是+、-、*、/、^、(、)
(4)可以判断表达式的合法性(如括号的匹配)
写作业时遇到的一道题目,觉得比较麻烦,估计以后会有人遇到相同的问题,就写了篇博客记录下来。
主要思路:
(1)先将表达式转化成后缀表达式
(2)逐个读取后缀表达式,计算结果
转化成后缀表达式:
(1)设立操作符栈。
(2)设表达式的结束符为“#”,预设操作符栈的栈底为“#”。
(3)若当前字符是操作数,则直接发送给后缀式。
(4)若当前字符为操作符且优先级大于栈顶操作符,则人栈,否则退出栈顶操作符发送给后缀式。
(5)若当前字符是结束符,则自栈顶至栈底依次将栈中所有操作符发送给后缀式。
(6)“(”对它之前后的操作符起隔离作用,则若当前操作符为“(”时人栈。
(7)“)”可视为自相应左括号开始表达式的结束符,则从栈顶起,依次退出栈顶操作
符发送给后缀式直至栈顶字符为“("止。“(”不发送到后缀式。
转化成后缀表达式函数代码:
/*SeqStack *L操作符栈,char *str1读取的表达式,char *str2返回的后缀表达式*/
void Conversion(SeqStack *S,char *str1,char *str2)
{
int i=0;
char *p=str1,e;
//预设操作符栈的栈底为“#”
Push(S,'#');
while (*p!='\0')
{
//若当前字符不是操作符是操作数,则直接发送给后缀式。
if (!Isoperator(*p))
{
str2[i++]=*p;
}
else
{
if (*p=='(')
Push(S,*p);
else if (*p==')')
{
while(GetTop(S)!='(')
{
Pop(S,&e);
str2[i++]=e;
}
Pop(S,&e); /*pop掉前括号*/
}
else if (*p=='#')
{
while (!IsEmpty(S))
{
Pop(S,&e);
str2[i++]=e;
}
}
else if (Compare(*p,GetTop(S)))
{
Push(S,*p);
}
else if (!Compare(*p,GetTop(S)))
{
Pop(S,&e);
str2[i++]=e;
continue; /*continue应该要加*/
}
}
p++;
}
str2[i-1]='\0'; /*#号也存进去了,所以用'\0'覆盖掉*/
}
完整计算表达式代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define TRUE 1
#define FALSE 0
#define Stack_Size 50
char ops[8]= {'+','-','*','/','(',')','^','#'}; /*运算符数组*/
int priority[8] = {1,1,2,2,0,0,3,-1};
typedef struct
{
char elem[Stack_Size];
int top;
} SeqStack; /*运算符栈的定义*/
typedef struct
{
int elem[Stack_Size];
int top;
} nSeqStack; /* 运算数栈的定义*/
void InitStack(SeqStack *S) /*初始化运算符栈*/
{
S->top =-1;
}
void InitStackn(nSeqStack *S) /*初始化运算数栈*/
{
S->top =-1;
}
int IsEmpty(SeqStack *S) /*判断栈S为空栈时返回值为真,反之为假*/
{
return(S->top==-1?TRUE:FALSE);
}
int IsEmptyn(nSeqStack *S) /*判断栈S为空栈时返回值为真,反之为假*/
{
return(S->top==-1?TRUE:FALSE);
}
/*判栈满*/
int IsFull(SeqStack *S) /*判断栈S为满栈时返回值为真,反之为假*/
{
return(S->top==Stack_Size-1?TRUE:FALSE);
}
int IsFulln(nSeqStack *S) /*判断栈S为满栈时返回值为真,反之为假*/
{
return(S->top==Stack_Size-1?TRUE:FALSE);
}
int Push(SeqStack *S, char x) /*运算符栈入栈函数*/
{
if (S->top==Stack_Size-1)
{
printf("Stack is full!\n");
return FALSE;
}
else
{
S->top++;
S->elem[S->top]=x;
return TRUE;
}
}
int Pushn(nSeqStack *S, int x) /*运算数栈入栈函数*/
{
if (S->top==Stack_Size-1)
{
printf("Stack is full!\n");
return FALSE;
}
else
{
S->top++;
S->elem[S->top]=x;
return TRUE;
}
}
int Pop(SeqStack *S, char *x) /*运算符栈出栈函数*/
{
if (S->top==-1)
{
printf("运算符栈空!\n");
return FALSE;
}
else
{
*x=S->elem[S->top];
S->top--;
return TRUE;
}
}
int Popn(nSeqStack *S, int *x) /*运算数栈出栈函数*/
{
if (S->top==-1)
{
printf("运算数栈空!\n");
return FALSE;
}
else
{
*x=S->elem[S->top];
S->top--;
return TRUE;
}
}
char GetTop(SeqStack *S) /*运算符栈取栈顶元素函数*/
{
if (S->top ==-1)
{
printf("运算符栈为空!\n");
return FALSE;
}
else
{
return (S->elem[S->top]);
}
}
int GetTopn(nSeqStack *S) /*运算数栈取栈顶元素函数*/
{
if (S->top ==-1)
{
printf("运算符栈为空!\n");
return FALSE;
}
else
{
return (S->elem[S->top]);
}
}
int Isoperator(char ch) /*判断输入字符是否为运算符函数,是返回TRUE,不是返回FALSE*/
{
int i;
for (i=0; i<8; i++)
{
if(ch==ops[i])
return TRUE;
}
return FALSE;
}
int Compare(char c1,char c2)
{
int m,n;
/*赋值c1对应的n*/
if (c1=='+' || c1=='-')
m=1;
else if (c1=='*' || c1=='/')
m=2;
else if (c1=='(' || c1==')')
m=0;
else if (c1=='^')
m=3;
else if (c1=='#')
m=-1;
/*赋值c2对应的n*/
if (c2=='+' || c2=='-')
n=1;
else if (c2=='*' || c2=='/')
n=2;
else if (c2=='(' || c2==')')
n=0;
else if (c2=='^')
n=3;
else if (c2=='#')
n=-1;
return m>n;
}
/*SeqStack *L操作符栈,char *str1读取的表达式,char *str2返回的后缀表达式*/
void Conversion(SeqStack *S,char *str1,char *str2)
{
int i=0;
char *p=str1,e;
//预设操作符栈的栈底为“#”
Push(S,'#');
while (*p!='\0')
{
//若当前字符不是操作符是操作数,则直接发送给后缀式。
if (!Isoperator(*p))
{
str2[i++]=*p;
}
else
{
if (*p=='(')
Push(S,*p);
else if (*p==')')
{
while(GetTop(S)!='(')
{
Pop(S,&e);
str2[i++]=e;
}
Pop(S,&e); /*pop掉前括号*/
}
else if (*p=='#')
{
while (!IsEmpty(S))
{
Pop(S,&e);
str2[i++]=e;
}
}
else if (Compare(*p,GetTop(S)))
{
Push(S,*p);
}
else if (!Compare(*p,GetTop(S)))
{
Pop(S,&e);
str2[i++]=e;
continue; /*continue应该要加*/
}
}
p++;
}
str2[i-1]='\0'; /*#号也存进去了,所以用'\0'覆盖掉*/
}
int Calc(char *str)
{
nSeqStack *n,nn;
n=&nn;
int i;
int x,y,result;
char *p=str;
InitStackn(n);
while (*p!='\0')
{
if (!Isoperator(*p))
{
Pushn(n,*p-'0');
}
else
{
Popn(n,&x);
Popn(n,&y);
switch (*p)
{
case '+':
result=y+x;
break;
case '-':
result=y-x;
break;
case '*':
result=y*x;
break;
case '/':
result=y/x; /*假设都能整除*/
break;
case '^':
result=y;
for (i=1;i<x;i++)
{
result=result*y;
}
break;
default:
printf("error\n");
break;
}
Pushn(n,result);
}
p++;
}
return result;
}
int main()
{
/*
*整体步骤
*(1)表达式转化成后缀表达式
*(2)表达式逐个读取进行计算
*/
char str1[100],str2[100];
scanf("%s",str1);
SeqStack *s,ss;
s=&ss;
InitStack(s);
Conversion(s,str1,str2);
printf("后缀表达式:%s\n",str2);
int result = Calc(str2);
printf("表达式结果:%d\n",result);
return 0;
}
附:
利用后缀表达式求解,只需要从左向右依次扫描表达式,
(1)遇到操作数人栈,
(2)遇到操作符.则做出栈两次,获得两个操作数,
后出栈的操作数为第一个操作对象,对它们进行计算,
计算结果作为下次运算的操作数入栈。
重复上述操作,直到后缀表达式读取结束,既可完成表达式的计算。