问题标题: 表达式计算器(求大佬帮助)

1
0
已解决
王梓轩
王梓轩
资深光能
资深光能

谁能改成有括号的?

#include<bits/stdc++.h>
#include<windows.h>
#include<mmsystem.h>
#include<locale.h>
#include<direct.h>
#include<tchar.h>
#include<conio.h>
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize(2)
#pragma comment(lib,"winmm.lib")
#define KEY_DOWN(VK_NONAME)((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
/*函数提前声明*/
/*-----------------------------*/
string PLUS(string,string);
string MINUS(string,string);
string MUL(string,string);
string DIV(string,string,int);
bool bijiao(string,string);
bool judge(string);
/*-----------------------------*/
string PLUS(string a,string b)//高精度加法
//循环次数≈a.size()*1.5
{
	string c="";//结果
	int flag=0;//负数标志
	if(a[0]=='-'&&b[0]=='-')
		flag=1,a.erase(0,1),b.erase(0,1);//都是负数,去除'-',答案加上'-'
	if(b[0]=='-'&&a[0]!='-')swap(a,b);//对下一步预处理
	if(a[0]=='-'&&b[0]!='-')//一个是负数,一个不是
	{
		a.erase(0,1);//去掉'-'
		if(a==b)return "0";//相等为0
		return bijiao(a,b)?'-'+MINUS(a,b):MINUS(b,a);//判断大小做减法
	}
	int carry=0;//进位+a[i]+b[j]
	//没有使用逆序,时间复杂度优化
	for(int i=a.size()-1,j=b.size()-1; i>=0||j>=0; i--,j--)//i遍历a,j遍历b
	{
		if(i>=0)carry+=a[i]-'0';//加a[i]
		if(j>=0)carry+=b[j]-'0';//加b[j]
		c+=carry%10+'0';//加上末位,其余进位
		carry/=10;//去掉最后一位,下次进位
	}
	if(carry)c+=carry%10+'0';//还能进一位
	if(flag)c+='-';//负数
	for(int i=0; i<c.size()/2; i++)swap(c[i],c[c.size()-1-i]);//优化逆序
	return c;//返回值
}
/*-----------------------------*/
string MINUS(string a,string b)//高精度减法
//循环次数:a.size()*2
{
	int flag=0;//负数标志
	if(a==b)return "0";//结果为0的特判
	if(b[0]=='-')//b是负数,跳转至加法
	{
		b.erase(0,1);//去掉b的'-',做加法
		return PLUS(a,b);//加法
	}
	if(a[0]=='-'&&b[0]!='-')//a是负数,b不是负数
	{
		a.erase(0,1);//去掉a的'-',做加法
		return '-'+PLUS(a,b);//结果必定为负数
	}
	if((a.size()==b.size()&&a<b)||a.size()<b.size())
		swap(a,b),flag=1;//a比b小,交换,标记结果负数
	int carry;//每一位
	string c="";
	for(int i=a.size()-1,j=b.size()-1; i>=0||j>=0; i--,j--)//i遍历a,j遍历b
	{
		carry=0;
		if(i>=0)carry+=a[i];//防止某一个变量<0
		if(j>=0)carry-=b[j]-'0';//防止某一个变量<0
		if(carry<'0')a[i-1]--,carry+=10;//结尾(若a[i-1]=='0',也没有问题,'0'-1-'0'==-1)
		c+=carry;//c加上这一位
	}
	while(c[c.size()-1]=='0'&&c.size()>0)c.erase(c.size()-1,1);//去除前缀0
	if(flag)c+='-';//负数
	for(int i=0; i<c.size()/2; i++)swap(c[i],c[c.size()-1-i]);//优化逆序
	return c;//返回值
}
/*-----------------------------*/
string MUL(string a,string b)//高精度乘法
//循环次数:a.size()*b.size()+a.size()+b.size()
{
	string ans="";//结果
	int flag=0;
	if(a[0]=='-'&&b[0]!='-')flag=1,a.erase(0,1);//a是负数,b不是
	if(b[0]=='-'&&a[0]!='-')flag=1,b.erase(0,1);//b是负数,a不是
	if(a[0]=='-')a.erase(0,1);//去a的'-'
	if(b[0]=='-')b.erase(0,1);//去b的'-'
	short c[1000005]= {0};//数位用short(-32768~32767)
	int k=a.size()+b.size()+1;//结果位数最大
	for(int i=a.size()-1; i>=0; i--)//双重循环遍历,不使用逆序,优化时间复杂度
		for(int j=b.size()-1; j>=0; j--)
		{
			int iplusj=a.size()-i-1+b.size()-j-1;//过程较复杂,提前存好
			c[iplusj]+=(a[i]-'0')*(b[j]-'0');//逐位相乘
			c[iplusj+1]+=c[iplusj]/10;//进位
			c[iplusj]%=10;//保留个位
		}
	while(c[k]==0&&k>=0)k--;//去除前缀0
	while(k>=0)ans+=c[k--]+'0';//结果
	if(flag)return '-'+ans;//负数
	return ans;//无负数
}
bool bijiao(string a,string b)
{
	if(a.size()>b.size()||a.size()==b.size()&&a>=b)return 1;//比较大小
	return 0;
}
string DIV(string a,string b,int x)//高精度除法
{
	if(b=="0")exit(0);//除数为0,这里使用c语言的退出程序
	int flag=0,flagg=0;//负数
	string c;//商
	if(a[0]=='-')a.erase(0,1),flag=1,flagg=1;//a是负数
	if(b[0]=='-')//b是负数
	{
		b.erase(0,1);//删除'-'
		if(flag==1)flag=0;//取反
		else flag=1;//取反
	}
	int t=b.size();//b的初始长度
	for(int i=b.size(); i<a.size(); i++)b+='0';//把b的位数变得和a一样大
	while(t<=b.size())//b不能改变本身
	{
		int s=0;//该位的值
		while(bijiao(a,b))//a必须比b大
		{
			a=MINUS(a,b);//做减法
			s++;//这一位+1
		}
		b.erase(b.size()-1,1);//删除b的最后一位(0)
		c+=s+'0';//c加上这一位
	}
	while(c[c.size()-1]=='0'&&c.size()>1)c.erase(c.size()-1,1);//去除前缀0
	if(x==1)//取商
	{
		if(flag)return '-'+c;//负数
		return c;//结果
	}
	else//取余数
	{
		if(flagg)return '-'+a;//负数
		return a;//结果
	}
}
bool judge(string a)//判断表达式合法(该区域有BUG,无法判断括号是否正常,此代码不会计算括号)
{
	for(int i=1; i<a.size()-1; i++)//遍历表达式
	{
		if(isdigit(a[i])||//数字
		        ((a[i]=='('&&//左括号
		          isdigit(a[i+1])&&
		          (a[i-1]=='+'||
		           a[i-1]=='-'||
		           a[i-1]=='*'||
		           a[i-1]=='/'||
		           a[i-1]==' ')&&isdigit(a[i+1]))||
		         (a[i]==')'&&
		          (a[i+1]=='+'||
		           a[i+1]=='-'||
		           a[i+1]=='*'||
		           a[i+1]=='/'||
		           a[i+1]==' ')&&isdigit(a[i-1]))))continue;//数字或者符号,合理
		else if(a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/')//符号且有数字在两边,合理
			if((isdigit(a[i-1])||a[i-1]==')')&&(isdigit(a[i+1])||a[i+1]=='('))continue;
			else if((a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/')&&a[i+1]=='-')//负数,合理
			{
				i++;
				continue;
			}
			else if(a[i]=='-'&&i==1)continue;//开头负数,合理
		return 0;//不合理
	}
	for(int i=1; i<a.size()-1; i++)
		if(a[i]=='(')
		{
			int flag=0;
			for(int j=a.size(); j>=i+1; j--)
			{
				if(a[j]==')')
				{
					flag=1;
					if(!judge(a.substr(i+1,j-1)))return 0;
				}
			}
			if(flag==0)return 0;
		}
	return 1;
}
void clearbug(string a)//把所有--删除
{
	for(int i=1; i<a.size()-2; i++)if(a[i]=='-'&&a[i+1]=='-')a.erase(i,2);
}
string wkhbds(string a)//无括号表达式的计算
{
	for(int i=1; i<a.size()-1; i++)//遍历
	{
		if(a[i]=='*')//乘法
		{
			//字符串模拟
			/*-------------------------------------*/
			int begin,end;
			for(int j=i-1; j>=1; j--)
				if((isdigit(a[j])||a[j]=='-')&&(a[j-1]=='+'||a[j-1]=='-'||a[j-1]=='*'||a[j-1]=='/'||a[j-1]==' '))
				{
					begin=j;
					if(isdigit(a[j])&&(a[j-2]=='+'||a[j-2]=='-'||a[j-2]=='*'||a[j-2]=='/'||a[j-2]==' '))begin=j-1;
					break;
				}
			for(int j=i+1; j<=a.size()-1; j++)
				if(isdigit(a[j])&&(a[j+1]=='+'||a[j+1]=='-'||a[j+1]=='*'||a[j+1]=='/'||a[j+1]==' '))
				{
					end=j;
					break;
				}
			/*-------------------------------------*/
			string z=a.substr(begin,i-begin),y=a.substr(i+1,end-i);//两个乘数
			a.erase(begin,end-begin+1);//删除两个数的表达式
			a.insert(begin,MUL(z,y));//换成结果
			i=begin;//将i设为begin,继续遍历
			clearbug(a);//删除所有--
//			cout<<a.substr(1,a.size()-2)<<endl;
		}
		if(a[i]=='/')//除法,注释略
		{
			int begin,end;
			for(int j=i-1; j>=1; j--)
				if((isdigit(a[j])||a[j]=='-')&&(a[j-1]=='+'||a[j-1]=='-'||a[j-1]=='*'||a[j-1]=='/'||a[j-1]==' '))
				{
					begin=j;
					if(isdigit(a[j])&&(a[j-2]=='+'||a[j-2]=='-'||a[j-2]=='*'||a[j-2]=='/'||a[j-2]==' '))begin=j-1;
					break;
				}
			for(int j=i+1; j<=a.size()-1; j++)
				if(isdigit(a[j])&&(a[j+1]=='+'||a[j+1]=='-'||a[j+1]=='*'||a[j+1]=='/'||a[j+1]==' '))
				{
					end=j;
					break;
				}
			string z=a.substr(begin,i-begin),y=a.substr(i+1,end-i);
			a.erase(begin,end-begin+1);
			a.insert(begin,DIV(z,y,1));
			i=begin;
			clearbug(a);
//			cout<<a.substr(1,a.size()-2)<<endl;
		}
	}
	for(int i=1; i<a.size()-1; i++)//加减法,注释略
	{
		if(a[i]=='+')
		{
			int begin,end;
			for(int j=i-1; j>=1; j--)
				if((isdigit(a[j])||a[j]=='-')&&(a[j-1]=='+'||a[j-1]=='-'||a[j-1]=='*'||a[j-1]=='/'||a[j-1]==' '))
				{
					begin=j;
					if(isdigit(a[j])&&(a[j-2]=='+'||a[j-2]=='-'||a[j-2]=='*'||a[j-2]=='/'||a[j-2]==' '))begin=j-1;
					break;
				}
			for(int j=i+1; j<=a.size()-1; j++)
				if(isdigit(a[j])&&(a[j+1]=='+'||a[j+1]=='-'||a[j+1]=='*'||a[j+1]=='/'||a[j+1]==' '))
				{
					end=j;
					break;
				}
			string z=a.substr(begin,i-begin),y=a.substr(i+1,end-i);
			a.erase(begin,end-begin+1);
			a.insert(begin,PLUS(z,y));
			i=begin;
			clearbug(a);
//			cout<<a.substr(1,a.size()-2)<<endl;
		}
		if(a[i]=='-')
		{
			int cnt=0;//统计'-'的出现次数
			for(int j=1; j<a.size()-2; j++)if(a[j]=='+'||a[j]=='-'||a[j]=='*'||a[j]=='/')cnt++;//遍历
			if(cnt==1&&i==1)break;//在第一位出现,只有一个负数,退出循环
			if(i==1)continue;//首位的负数 
			int begin,end;
			for(int j=i-1; j>=1; j--)
				if((isdigit(a[j])||a[j]=='-')&&(a[j-1]=='+'||a[j-1]=='-'||a[j-1]=='*'||a[j-1]=='/'||a[j-1]==' '))
				{
					begin=j;
					if(isdigit(a[j])&&(a[j-2]=='+'||a[j-2]=='-'||a[j-2]=='*'||a[j-2]=='/'||a[j-2]==' '))begin=j-1;
					break;
				}
			for(int j=i+1; j<=a.size()-1; j++)
				if(isdigit(a[j])&&(a[j+1]=='+'||a[j+1]=='-'||a[j+1]=='*'||a[j+1]=='/'||a[j+1]==' '))
				{
					end=j;
					break;
				}
			string z=a.substr(begin,i-begin),y=a.substr(i+1,end-i);
			a.erase(begin,end-begin+1);
			a.insert(begin,MINUS(z,y));
			i=begin;
			clearbug(a);
			if(cnt==1)break;//计算完最后的减法,完成
//			cout<<a.substr(1,a.size()-2)<<endl;
		}
	}
	return a.substr(1,a.size()-2);//返回值
}
int main()
{
	string a;//表达式
	getline(cin,a);//输入a
	if(a[0]=='-')a='0'+a;//-1==0-1
	a=' '+a+' ';//字符串模拟
	if(!judge(a))//表达式合法问题
	{
		cout<<"表达式不合法!";
		return 0;
	}
	cout<<wkhbds(a);//输出
}

 

王梓轩在2023-05-19 20:39:17追加了内容

ding


0
已采纳
吴章鹏
吴章鹏
中级光能
中级光能
//高精度加法
string ADD_PARENTHESES(string origin){//函数名已贴合意义
    string res(origin);
    string ans = "";
    int right = -1; // 暂时存储右括号所在下标
    for(int i = 0 ; i < res.size() ; ++i){
        if(res[i] == '+' || res[i] == '*' || res[i] == '-'){
            ans += '(';
            bool flag = 1;
            if(res[0] == '-') ans+= '(', ans+=res[0], res = res.substr(1), flag = 0; 
            for(int j = 0 ; j < res.size() ; ++j){
                if(res[j] == res[i] && j < i){ans+=res[j]; continue;}//此时为前方隐含乘号 或者是只有首位负号的情况
                ans+=res[j];
                if(flag&&res[j] == '-'){ans += '(', res = res.substr(j+1) , j = -1, right = -2; flag = 0;} //flag为了只在第一次遇到负号后添加括号
                if(flag&&res[j] == '+'){ans += '(', res = res.substr(j+1) , j = -1, right = -3; flag = 0;}
                if(flag&&res[j] == '*'){ans += '(', res = res.substr(j+1) , j = -1, right = -4; flag = 0;}
                if(right == -2 && res[j] == ')'){ans += ')'; right = -1; if(j != res.size() - 1) ans += '*';}
                if(right == -3 && res[j] == ')'){ans += ')'; right = -1; if(j != res.size() - 1) ans += '+';}
                if(right == -4 && res[j] == ')'){ans += ')'; right = -1; if(j != res.size() - 1) ans += '*';}
            }
            ans += ')';
            return ans;
        }
    }
    return origin;  //可能不存在符号的情况
} 

?

0
0
0
吴章鹏
吴章鹏
中级光能
中级光能

到洛谷一趟!

紧急通知!

我要回答