用C语言中栈的思想实现加减乘除四则运算和括号的计算器

设计思路

将每个运算符设置优先级,运用栈先入后出的思想,从左到右扫描输入到电脑上的计算公式,将扫描到的数字数据和字符数据的优先级分别存入两个数组,再依次从两个数组中弹出对应的数据和计算符号进行计算。

主要问题

1.如何让计算机实现正确的符号计算顺序?
为每个符号设定相应的优先级,在这个程序中我将+,-优先级设置为1,*,/设置为2,(设置为3,)设置为0,=设置为-1,也就是最低等。
在从左到右扫描代数式时,若下一位符号优先级更大,则改符号可以直接推入存储符号的栈中;若下一位符号优先级相比较小,则在数字栈弹出两个数字,在符号位弹出一个符号进行运算。

符号| 序号 | 优先级 |
+| -7 | 1 |
–| -6 | 1 |
x | -5 | 2 |
/ | -4 | 2 |
( | -3 | 3 |
) | -2 | 0 |
=| -1 | -1|

2.如何实现多位数的扫描?
设置rate变量,正常情况下rate为10,前面扫描得到的数据在下一次扫描时乘上10再加上后面扫描的数据,若遇到小数点的情况则rate变为0.1,且之后的每次扫描rate都应该缩小10倍

3.如何实现括号位的计算?
当遇到左括号时,因为左括号的优先级大于任何一个运算符,所以左括号可以直接压入栈中,在压入栈中之后将左括号运算符改为右括号运算符,为了让括号内的运算符也可以成功压入栈栈中。
遇到右括号运算符时,右括号运算符只比等号运算符优先级大,所以读取到右括号运算符后计算机会开始计算括号内的式子,计算完括号内的式子后直接将左括号运算符从栈内弹出。

数据结构和主要函数

Struct fuhao s[7]运用结构存放不同的操作符和对应的优先级;
Char str[30]用来存放输入的算式;
double a[20]用来存放运算的数据;
int b[20]用来存放操作符号所对应的在结构数组中的编号;

Void PUSH(nu,a[])为将操作数存放进数组a中;
void PUSH1(nu,b[])为将操作符号对应的序号存放进数组b中;
Double READ(*p)为读取字符串的数据,返回读取的数据;
Double POP(a[])为弹出a数组顶部的操作数,返回操作数;
int POP1(b[])为弹出b数组顶部的操作符对应序号;
Int t 用来判断情况,double ans为计算后的最终结果;

代码实现

#include <iostream>
using namespace std;
int lu=0;
struct fuhao
{
	char f;
	int x;
}s[7]={{'+',1},{'-',1},{'x',2},{'/',2},{'(',3},{')',0},{'=',-1}};
void PUSH(double nu,double a[])
{
	int i=0;
	for(;i<=20;i++)
		if(a[i]==9999)
			break;
	a[i]=nu;
}//常数入栈
void PUSH1(double nu,int b[])
{
	int i=0;
	for(;i<=20;i++)
		if(b[i]==9999)
			break;
	b[i]=nu;
}//符号优先级入栈
double READ(char *p)//从左往右读取
{
	double rate=10.0,item=0;
	int x=0;//表示读取的是数字还是符号
	p=p+lu;
	while(*p!='/n')
	{
		if(x==0)
		{
		if(*p=='+')
		{lu++;return -7;}//全局变量用来指示读取到的序号
		else if(*p=='-')
		{lu++;return -6;}
		else if(*p=='*')
		{lu++;return -5;}
		else if(*p=='/')
		{lu++;return -4;}
		else if(*p=='(')
		{lu++;return -3;}
		else if(*p==')')
		{lu++;return -2;}
		else if(*p=='=')
		{lu++;return -1;}
		else if(*p>='0'||*p<='9')//读取到数字数据
		{
			if(rate==10)
				item=item*rate+*p-'0';//转换为数字量
			else{
				item=item+(*p-'0')*rate;
				rate=rate/10;}//rate可以解决读取连续两个数的问题
			p++;
			lu++;
			x=1;
		}
		else//读取到不知名数字
		{
			cout<<"符号出错"<<endl;
			return -8;
		}
		}
		else
		{
			while(*p!='+'&&*p!='-'&&*p!='*'&&*p!='/'&&*p!='('&&*p!=')'&&*p!='=')//二重循环
				{
					if(*p=='.')
					rate=0.1;
					else
						{
			if(rate==10)
				item=item*rate+*p-'0';//rate如果为10则比率依然不改变
			else{
				item=item+(*p-'0')*rate;
				rate=rate/10;}
		}
		
            p++;
	    lu++;
	}
	return item;
}
	}
}
int TOP(int b[])
{
	int i=0;
	for(;i<20;i++)
		if(b[i]==9999)
		break;
	int c=b[i-1]+7;
	return c;
}//提取最上方的符号位的序号
double POP(double a[])
{
	int i=0;
	double h;
	for(;i<20;i++)
		if(a[i]==9999)
			break;
	h=a[i-1];
	a[i-1]=9999;
	return h;
}//弹出数据
int POP1(int b[])
{
	int i=0,h;
	for(;i<20;i++)
		if(b[i]==9999)
			break;
	h=b[i-1];
	b[i-1]=9999;//弹出后该位还原为9999
	return h+7;
}//弹出符号
int main()
{
	cout<<"请输入表达式:";
	char str[30];
	gets(str);//输入表达式
	int b[20],i,t=0,you,you1,you2,xu;//you表示读取的符号数
	double a[20],h,ans,op1,op2,op3;
	for(i=0;i<20;i++)
	{
		b[i]=9999;
		a[i]=9999;
	}//将两个数组都赋予初值最大值
	PUSH1(-1,b);//在b数组底部放入=号
	while(t!=2)//t表示三种情况,0表示读取数据,1表示计算数据,2表示得出结果
	{
		if(t==0)
		h=READ(str);
		if(h>=0)
		PUSH(h,a);	//read函数返回的数据大于0,数字入栈        
		else//读取到符号位
		{
			you1=h;//检测到下一个符号位
			you=TOP(b);//最上面符号的序号
			if(s[you].x<s[you1+7].x)//索引到符号位的优先级较大或者上一位为左括号则将符号压入栈中
			{
			PUSH1(h,b);
			t=0;
			you2=TOP(b);
			if(you2==4)//左括号位的处理,压入后成为右括号,优先级变为0
			{
				POP1(b);
				PUSH1(-2,b);//变为右括号
			}
			}
			else if(you==6&&h==-1)//读取的和栈最上面的符号都是“=”
			{
				ans=POP(a);
				t=2;
				cout<<"结果为:"<<ans;
			}
			else//压入的优先级小,需要进行计算
			{
				xu=POP1(b);//弹出顶层符号
				switch(xu)
				{
                case 0:op1=POP(a);op2=POP(a);op3=op2+op1;PUSH(op3,a);t=1;break;//将计算所得的数重新压入堆栈
				case 1:op1=POP(a);op2=POP(a);op3=op2-op1;PUSH(op3,a);t=1;break;
				case 2:op1=POP(a);op2=POP(a);op3=op2*op1;PUSH(op3,a);t=1;break;
				case 3:op1=POP(a);op2=POP(a);op3=op2/op1;PUSH(op3,a);t=1;break;
				case 5:t=0;break;//左括号直接省去,直接往后读一位,省略右括号
				default: cout<<"输入的计算式子错误"<<endl;t=2;break;//计算到没有显示的符号,输入的计算式错误
				}
			}
		}
	}
	system("pause");
	return 0;
}

有错误和改进欢迎大家指出啊!!!

  • 15
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
可以使用中缀表达式转后缀表达式的方法,然后使用计算后缀表达式的值。 具体步骤如下: 1. 定义一个用于存储运算符和数字,一个列表用于存储后缀表达式。 2. 遍历中缀表达式,如果是数字,则直接加入后缀表达式列表中;如果是左括号,则加入中;如果是右括号,则将中的运算符弹出,加入后缀表达式列表中,直到遇到左括号;如果是运算符,则将中优先级大于等于该运算符的运算符弹出,加入后缀表达式列表中,最后将该运算符入。 3. 遍历后缀表达式列表,如果是数字,则入;如果是运算符,则将顶的两个数字弹出,进行计算,并将结果入。 4. 中最后剩余的数字即为表达式的值。 代码实现如下: ```python def infix_to_postfix(expr): stack = [] # 运算符 postfix = [] # 后缀表达式 priorities = {'(': 0, '+': 1, '-': 1, '*': 2, '/': 2} # 运算符优先级 for token in expr: if token.isdigit(): # 如果是数字,直接加入后缀表达式 postfix.append(token) elif token == '(': stack.append(token) # 如果是左括号,入 elif token == ')': while stack and stack[-1] != '(': postfix.append(stack.pop()) # 如果是右括号,弹出中的运算符,并加入后缀表达式,直到遇到左括号 if stack and stack[-1] == '(': stack.pop() # 弹出左括号 else: while stack and priorities.get(stack[-1], -1) >= priorities.get(token, -1): postfix.append(stack.pop()) # 如果是运算符,弹出中优先级大于等于该运算符的运算符,并加入后缀表达式 stack.append(token) # 将该运算符入 while stack: postfix.append(stack.pop()) # 将中剩余的运算符加入后缀表达式 return postfix def eval_postfix(postfix): stack = [] # 数字 for token in postfix: if token.isdigit(): stack.append(int(token)) # 如果是数字,入 else: b = stack.pop() # 弹出顶的两个数字 a = stack.pop() if token == '+': stack.append(a + b) # 进行计算,并将结果入 elif token == '-': stack.append(a - b) elif token == '*': stack.append(a * b) elif token == '/': stack.append(a / b) return stack[-1] # 中剩余的数字即为表达式的值 expr = input('请输入含有四则运算带小括号的表达式:') postfix = infix_to_postfix(expr) value = eval_postfix(postfix) print('表达式的值为:', value) ``` 示例输入:`(1+2)*3-4/2` 示例输出:`表达式的值为:8.0`

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值