简易计算器(核心算法就是Shutting-Yard, 逆波兰式)

算法描述

INPUT: 需要解析转换的中缀表达式epr,epr是一个字符串

OUTPUT: epr相对应的后缀(逆波兰)表达式(存储在队列Q中)

 

初始化队列Q和符号栈S;

WHILEepr中还有内容未处理)

读取下一个标记单元(token),记做tk;

IFtk是数值) 将tk添加到队列Q中;

IFtk是函数名) 将tk压到栈S中;

IFtk是函数参数的逗号分隔符‘,’)

WHILES栈顶元素不是左括号‘()

将S栈顶元素出栈,添加到队列Q中;

IFS为空) 提示错误信息“逗号分隔符位置有误,或者括号不匹配”,终止;

 

IFtk是运算符)//不妨将tk对应的运算符记做op1

WHILES栈顶元素是运算符)//不妨将栈顶元素对应的运算符记做op2

IF((op1左结合 AND op1优先级≤op2优先级)ORop1优先级<op2优先级))

将S栈顶元素出栈,添加到队列Q中;

将tk压到栈S中;

 

IFtk是左括号‘(’) 将tk压到栈S中;

 

IFtk是右括号‘)’)

WHILES栈顶元素不是左括号‘()

将S栈顶元素出栈,添加到队列Q中;

IFS为空) 提示错误信息“括号不匹配”,终止;

ELSE 将S栈顶元素(即,左括号)出栈;

IFS栈顶元素是函数名) 将S栈顶元素出栈,添加到队列Q中;

 

WHILES非空

IFS栈顶元素是括号) 提示错误信息“括号不匹配”,终止;

将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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值