算法描述
INPUT: 需要解析转换的中缀表达式epr,epr是一个字符串
OUTPUT: 和epr相对应的后缀(逆波兰)表达式(存储在队列Q中)
初始化队列Q和符号栈S;
WHILE(epr中还有内容未处理)
读取下一个标记单元(token),记做tk;
IF(tk是数值) 将tk添加到队列Q中;
IF(tk是函数名) 将tk压到栈S中;
IF(tk是函数参数的逗号分隔符‘,’)
WHILE(S栈顶元素不是左括号‘(’)
将S栈顶元素出栈,添加到队列Q中;
IF(S为空) 提示错误信息“逗号分隔符位置有误,或者括号不匹配”,终止;
IF(tk是运算符)//不妨将tk对应的运算符记做op1
WHILE(S栈顶元素是运算符)//不妨将栈顶元素对应的运算符记做op2
IF((op1左结合 AND op1优先级≤op2优先级)OR(op1优先级<op2优先级))
将S栈顶元素出栈,添加到队列Q中;
将tk压到栈S中;
IF(tk是左括号‘(’) 将tk压到栈S中;
IF(tk是右括号‘)’)
WHILE(S栈顶元素不是左括号‘(’)
将S栈顶元素出栈,添加到队列Q中;
IF(S为空) 提示错误信息“括号不匹配”,终止;
ELSE 将S栈顶元素(即,左括号)出栈;
IF(S栈顶元素是函数名) 将S栈顶元素出栈,添加到队列Q中;
WHILE(S非空)
IF(S栈顶元素是括号) 提示错误信息“括号不匹配”,终止;
将S栈顶元素出栈,添加到队列Q中;
return 队列Q;
3)算例:3 + 4 * 2 / Pow(Pow(1 - 5, 2),2)
Token | Action | output Queue Q | Operator Stack S | Notes |
3 | Add token to output queue | 3 |
| The most left is front-of-queue/top-of-stack |
+ | Push token to stack | 3 | + |
|
4 | Add token to output queue | 3 4 | + |
|
* | Push token to stack | 3 4 | * + | '*' has hihger precedence than '+' |
2 | Add token to output queue | 3 4 2 | * + |
|
/ | Pop operator to output queue | 3 4 2 * | + | '/' has the same precedence with '*' and is left-associative |
Push token to stack | 3 4 2 * | / + | ||
Pow | Push funtion token to stack | 3 4 2 * | Pow / + |
|
( | Push l-parenthesis to stack | 3 4 2 * | ( Pow / + |
|
Pow | Push funtion token to stack | 3 4 2 * | Pow ( Pow / + |
|
( | Push l-parenthesis to stack | 3 4 2 * | ( Pow ( Pow / + |
|
1 | Add token to output queue | 3 4 2 * 1 | ( Pow ( Pow / + |
|
- | Push token to stack | 3 4 2 * 1 | - ( Pow ( Pow / + |
|
5 | Add token to output queue | 3 4 2 * 1 5 | - ( Pow ( Pow / + |
|
, | Pop operator to output queue | 3 4 2 * 1 5 - | ( Pow ( Pow / + | ',' is function argument separator,so pop operators off the stack onto the output queue until the token at the top of the stack is a left parenthesis |
2 | Add token to output queue | 3 4 2 * 1 5 - 2 | ( Pow ( Pow / + |
|
) | Remove l-parenthesis from stack | 3 4 2 * 1 5 - 2 | Pow ( Pow / + |
|
Pop function token to output | 3 4 2 * 1 5 - 2 Pow | ( Pow / + | ||
, | Do nothing | 3 4 2 * 1 5 - 2 Pow | ( Pow / + | ',' is function argument separator,but '(' is at the top of stack |
2 | Add token to output | 3 4 2 * 1 5 - 2 Pow 2 | ( Pow / + |
|
) | Remove l-parenthesis from stack | 3 4 2 * 1 5 - 2 Pow 2 | Pow / + |
|
Pop function token to output | 3 4 2 * 1 5 - 2 Pow 2 Pow | / + | ||
NULL | Pop operator to output | 3 4 2 * 1 5 - 2 Pow 2 Pow / | + | No more tokens to read |
NULL | Pop operator to output | 3 4 2 * 1 5 - 2 Pow 2 Pow / + |
|
|
|
|
|
|
|
|
|
|
|
过程应该都能理解吧,不理解的可以留言问我。同时觉得有更好的想法的,可以留言提醒我哦。
个人的源代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
const int N=100;
double var=0, uar=0, war=0;
/***********************结点结构体**************************/
struct all
{
char type[5]; //结点的类型:db(double), char, var(变量), han(函数)
double num; //装载数字
char fu; //装载运算符
char var[5]; //装载变量
char han[5]; //装载函数
};
/**************************栈*******************************/
struct stack
{
all elem[N]; //栈结点
int len; //len为长度
};
//初始化栈
void InitStack(stack *&S)
{
memset(S->elem, 0, sizeof(all)*N);
S->len=0;
}
//判断栈是否为空
bool EmptyStack(stack *S)
{
return (S->len==0)?true:false;
}
//结点n进栈
void StackPush(stack *&S, all n)
{
S->elem[S->len]=n;
S->len++;
}
//栈顶元素出栈,并将栈顶元素保留在n中,若栈空则返回失败
bool StackPop(stack *&S, all &n)
{
if(EmptyStack(S)) return false;
n=S->elem[S->len-1];
S->len--;
return true;
}
/**************************队列*******************************/
struct queue
{
all elem[N];
int len;
};
//初始化队列
void InitQueue(queue *&Q)
{
memset(Q->elem, 0, sizeof(all)*N);
Q->len=0;
}
//判断队列是否为空
bool EmptyQueue(queue *Q)
{
return (Q->len==0)?true:false;
}
//结点n进队
void QueuePush(queue *&Q, all n)
{
Q->elem[Q->len]=n;
Q->len++;
}
//队首元素出队,并将队首元素保存在n中,若队列以空,则返回失败
bool QueuePop(queue *&Q, all &n)
{
if(EmptyQueue(Q)) return false;
n=Q->elem[0];
for(int i=0; i<Q->len-1; i++)
{
Q->elem[i]=Q->elem[i+1];
}
Q->len--;
return true;
}
/*****************************ShuttingYard算法***********************************/
//一个返回10的m次方的函数
double power(int m)
{
int temp=1;
m--;
while(m--)
{
temp=temp*10;
}
return temp;
}
//把数字字符串转化为double型的数字
double change(char num[])
{
int i, j;
int len=strlen(num);
double sum=0.0;
for(i=0; i<len; i++)
{
if(num[i] == '.') break;
}
if(i == len-1)
{
for(j=0; j<i; j++)
{
sum+=pow(10, i-j)*(num[i]-'0');
}
}
else
{
for(j=0; j<i; j++)
{
sum+=pow(10,i-j-1)*(num[j]-'0');
}
for(j=i+1; j<len; j++)
{
sum+=pow(10,(j-i)*(-1))*(num[j]-'0');
}
}
return sum;
}
//中缀表达式转后缀
//思路就是从头开始遍历mid数组,若碰到数字的字符串temp(如:3.14)则将其转换为double型放入队列Q中
//若碰到'+' || '-' || '*' || '/' || 'pow'(一个函数,用来求n的m次方) || 'sqrt'(一个函数,用来求n的开平方) || '=',
//则将其压进符号栈S,若进栈元素为'+' || '-'则先检测栈顶元素的优先级是否大于进栈元素的优先级,若是则将栈顶元素出栈
//把出栈的元素进队列Q中,然后进栈元素再进栈,否则直接让进栈元素进栈
//若碰到')'则让符号栈依次出栈,并将出栈元素依次压进队列中,直到碰到'('或者栈空为止,出栈'(',
//然后再检测栈顶元素是否为函数,若是则将其出栈并压进队列中,否则进入下一轮检测
//最终循环结束,返回队列Q
queue ShuttingYard(char mid[])
{
int i, j;
queue *Q=new queue;
InitQueue(Q);
stack *S=new stack;
InitStack(S);
bool flag = false;
for(i=0; i<strlen(mid); i++)
{
if(mid[i]>='0' && mid[i]<='9')
{
char temp[10]={0};
for(j=i; j<strlen(mid); j++)
{
if(mid[j] == '.')
{
temp[j-i]=mid[j];
continue;
}
if(mid[j] < '0' || mid[j] > '9')
{
i=j-1;
break;
}
temp[j-i]=mid[j];
}
all t;
char db[3]={"db"};
strcpy(t.type, db);
t.num=change(temp);
if(flag == true)
{
t.num=-1*t.num;
flag = false;
}
QueuePush(Q, t);
}
else if(mid[i] == '(')
{
all t;
char ch[5]={"char"};
strcpy(t.type,ch);
t.fu='(';
StackPush(S, t);
}
else if(mid[i] == ')')
{
all t;
while(!EmptyStack(S) && (StackPop(S, t) && t.fu != '('))
{
QueuePush(Q, t);
}
if(!EmptyStack(S))
{
StackPop(S, t);
if(t.type[0] == 'p' || t.type[0] == 's')
{
QueuePush(Q, t);
}
else
{
StackPush(S, t);
}
}
}
else
{
if(mid[i] == '=')
{
all t;
char ch[5]={"char"};
strcpy(t.type, ch);
t.fu='=';
StackPush(S, t);
}
if(mid[i] == 'v' || mid[i] == 'u' || mid[i] == 'w')
{
int tmp=i;
char temp[10]={0};
for(j=i; j < strlen(mid); j++)
{
if(mid[j] <'a' || mid[j] > 'z')
{
i=j-1;
break;
}
temp[j-i]=mid[j];
}
if(tmp==0)
{
all t;
strcpy(t.type, temp);
strcpy(t.var, temp);
QueuePush(Q, t);
}
else
{
all t;
char db[3]={"db"};
strcpy(t.type, db);
if(temp[0] == 'v')
{
t.num=var;
}
else if(temp[0] == 'u')
{
t.num=uar;
}
else t.num=war;
QueuePush(Q, t);
}
}
if(mid[i] == 'p' || mid[i] == 's')
{
char temp[10]={0};
for(j=i; j < strlen(mid); j++)
{
if(mid[j] <'a' || mid[j] > 'z')
{
i=j-1;
break;
}
temp[j-i]=mid[j];
}
all t;
strcpy(t.type, temp);
strcpy(t.han, temp);
StackPush(S, t);
}
if(mid[i] == '+' || mid[i] == '-')
{
all t;
if(mid[i] == '-')
{
if(mid[i-1] == '=' || mid[i-1] == '(')
{
flag = true;
continue;
}
}
if(S->elem[S->len-1].fu == '*' || S->elem[S->len-1].fu == '/')
{
StackPop(S, t);
QueuePush(Q, t);
}
char ch[5]={"char"};
strcpy(t.type, ch);
t.fu=mid[i];
StackPush(S, t);
}
if(mid[i] == '*' || mid[i] == '/')
{
all t;
char ch[5]={"char"};
strcpy(t.type, ch);
t.fu=mid[i];
StackPush(S, t);
}
}
}
while(!EmptyStack(S))
{
all t;
StackPop(S, t);
QueuePush(Q, t);
}
return *Q;
}
/********************************通过返回的Q队列求结果*********************************/
//通过后缀表达式队列Q来求得整个算式的结果
//思路是这样的,先依次遍历队列的元素,检测元素的类型
//若为char类型,则为四则运算符和等于号,若为四则运算符则把(设当前为第i个元素)第i个,第i-1个,第i-2个元素出队列
//把第i-1个元素和第i-2个元素运算结果放回第i-2元素的位置中,此时,队列长度-2,当前指针-2,继续遍历,若为等于号
//则将第i个,第i-1个,第1个元素出队列,把第i-1个元素的数值(sum值)放到第i-2个元素中,第i-2个元素进回原来的队伍位置
//此时队列长度-2,当前指针-2
//若为han类型,则为函数运算符,若为pow(n, m)则把(设当前为第i个元素)第i个,第i-1个,第i-2个元素出队列
//把第i-1个元素和第i-2个元素运算结果放回第i-2元素的位置中,此时,队列长度-2,当前指针-2,继续遍历,
//若为sqrt(n)则把(设当前为第i个元素)第i个,第i-1个元素出队列,把运算结果放回i-1的位置中,此时队列长度-1,当前指针-1,继续遍历
//最终得到结果放到变量中去
void reslut(queue *Q)
{
int i, j, len=Q->len;
double sum=0.0;
all t;
for(i=0; i<len; i++)
{
if(Q->elem[i].type[0] == 'c')
{
if(Q->elem[i].fu == '*')
{
char db[3]={"db"};
strcpy(t.type, db);
t.num=Q->elem[i-2].num * Q->elem[i-1].num;
Q->elem[i-2]=t;
for(j=i-1; j<len; j++)
{
Q->elem[j]=Q->elem[j+2];
}
len=len-2;
i=i-2;
}
else if(Q->elem[i].fu == '/')
{
char db[3]={"db"};
strcpy(t.type, db);
t.num=Q->elem[i-2].num / Q->elem[i-1].num;
Q->elem[i-2]=t;
for(j=i-1; j<len; j++)
{
Q->elem[j]=Q->elem[j+2];
}
len=len-2;
i=i-2;
}
else if(Q->elem[i].fu == '-')
{
char db[3]={"db"};
strcpy(t.type, db);
t.num=Q->elem[i-2].num - Q->elem[i-1].num;
Q->elem[i-2]=t;
for(j=i-1; j<len; j++)
{
Q->elem[j]=Q->elem[j+2];
}
len=len-2;
i=i-2;
}
else if(Q->elem[i].fu == '+')
{
char db[3]={"db"};
strcpy(t.type, db);
t.num=Q->elem[i-2].num + Q->elem[i-1].num;
Q->elem[i-2]=t;
for(j=i-1; j<len; j++)
{
Q->elem[j]=Q->elem[j+2];
}
len=len-2;
i=i-2;
}
else
{
printf("%s\n", Q->elem[0].type);
if(Q->elem[0].type[0] == 'v')
{
var=Q->elem[i-1].num;
}
else if(Q->elem[0].type[0] == 'u' )
{
uar=Q->elem[i-1].num;
}
else war=Q->elem[i-1].num;
len=len-2;
i=i-2;
}
}
else
{
if(Q->elem[i].type[0] == 'p')
{
char db[3]={"db"};
strcpy(t.type, db);
t.num=pow(Q->elem[i-2].num, Q->elem[i-1].num);
Q->elem[i-2]=t;
for(j=i-1; j<len; j++)
{
Q->elem[j]=Q->elem[j+2];
}
len=len-2;
i=i-2;
}
if(Q->elem[i].type[0] == 's')
{
char db[3]={"db"};
strcpy(t.type, db);
t.num=sqrt((double)Q->elem[i-1].num);
Q->elem[i-1]=t;
for(j=i; j<len; j++)
{
Q->elem[j]=Q->elem[j+1];
}
len=len-1;
i=i-1;
}
}
}
}
/******************************入口函数main*********************************/
int main()
{
int cmd;
char t[N]={0};
printf("|******************************简易计算器*******************************|\n");
printf("| 本计算器中设有三个变量(var, uar, war)用来存储结果值和替代常数 |\n");
printf("| 输入命令 [0](计算) 时,此时需要输入一串算术表达式,格式如下 |\n");
printf("| var=-1+pow(2,3)+sqrt(4)*(-1)/(-2) (注意:字符间不能有空格) |\n");
printf("| 输入命令 [1](查询变量值) 时,就会显示3个变量各自的值 |\n");
printf("| 输入命令 [2](变量值清零) 时,则三个变量值全部清0 |\n");
printf("| 输入命令 [3](退出)时,则退出计算器 |\n");
printf("|***********************************************************************|\n");
while(printf("请输入命令:\n") && scanf("%d", &cmd))
{
if(cmd==0)
{
memset(t, 0, sizeof(t));
printf("请输入一个算术表达式,格式如:var=-1+pow(2,3)+sqrt(4)*(-1)/(-2) (注意:字符间不能有空格)\n");
scanf("%s", t);
queue q=ShuttingYard(t);
reslut(&q);
system("CLS");
}
else if(cmd == 1)
{
printf("var=%lf\nuar=%lf\nwar=%lf\n", var, uar, war);
}
else if(cmd == 2)
{
var=uar=war=0.0;
system("CLS");
}
else if(cmd == 3)
{
break;
}
printf("|******************************简易计算器*******************************|\n");
printf("| 本计算器中设有三个变量(var, uar, war)用来存储结果值和替代常数 |\n");
printf("| 输入命令 [0](计算) 时,此时需要输入一串算术表达式,格式如下 |\n");
printf("| var=-1+pow(2,3)+sqrt(4)*(-1)/(-2) (注意:字符间不能有空格) |\n");
printf("| 输入命令 [1](查询变量值) 时,就会显示3个变量各自的值 |\n");
printf("| 输入命令 [2](变量值清零) 时,则三个变量值全部清0 |\n");
printf("| 输入命令 [3](退出)时,则退出计算器 |\n");
printf("|***********************************************************************|\n");
}
return 0;
}