题目分析:
这道题到目前为止,应该是编写的最麻烦的一个题了,实在没想到什么比较好的思路,写完了之后在网上也找了一圈,找了一个写的我觉得最好的,思路也差不多,不过实现起来,别人的代码还是简洁了很多,但是我感觉自己的代码看起来相对可能好理解一些?自恋一下。把大神的代码链接贴在文末,方便大家去观摩吧,现在自己写的代码肯定还是非常粗糙的,日子还长,希望能早些进步向诸位大神们靠近。
首先强调几个重要的需要注意的地方:
- 虽说题目说给出的分子分母都是整型范围内的,看到这个你就信了去开int,那你就真是天真的没边了。四则运算弄下来显然只要数据给的大点,要溢出那就是分分钟的事,所以老实点把所有的整型都用long long储存吧。可能有同学以前用Visual Studio的IDE,里面的长整型是__int64,这里不能用,PAT测评系统里边是不认的,PAT系统的注意事项里有说到。
- 关于符号的处理,如果你和我一样根据题目的意思单纯靠分子来判断正负号,那就得在计算除法的时候要注意点,因为一除那分子的负号就跑到分母去了,还需要额外处理一下。
别的地方,没有特别需要提的,不过要想把代码写的简单点,还是需要在写之前对代码的结构有一个大致的规划,考虑好数据结构。这题没有什么特别的算法,唯一可能说的上的就是求最大公约数的辗转相除法,相关内容网上很容易搜到,实现起来也容易,这里就不赘述。
我的代码主要框架是:
- 利用结构体 fraction 来表示分式的各个元素;
- 编写一个函数根据分子和分母来计算出相应的分数表达,赋值到相应的结构体中;
- 编写一个函数,用来输出给定四则运算符号下的运算表达式:
- 根据上述的这些基本函数,主函数只涉及读入数据然后调用这些函数即可。
源代码
#include <stdio.h>
#include <stdlib.h>
struct fraction{ //表示分式的结构体
char symbol='+';
long long inte; //带分数整数部分,整数运算后可能溢出,故用长整型
long long numerator;
long long denominator;
bool inf=false; //指示是否为无穷
};
long long gcd(long long a, long long b); //求最大公约数
void getFraction(long long num1,long long num2,fraction& f); //根据分子分母,构造出转换后的分式,并记录
void printFraction(const fraction& f1);
void ffoa(long long n11,long long n12,long long n21,long long n22,const char op,const fraction& p1,const fraction& p2); //按输入的运算符输出运算等式
int main()
{
long long num11,num12;
long long num21,num22;
scanf("%lld",&num11);
getchar(); //读取丢弃除号
scanf("%lld %lld",&num12,&num21);
getchar();
scanf("%lld",&num22);
fraction fl,fr;
getFraction(num11,num12,fl);
getFraction(num21,num22,fr);
ffoa(num11,num12,num21,num22,'+',fl,fr);
ffoa(num11,num12,num21,num22,'-',fl,fr);
ffoa(num11,num12,num21,num22,'*',fl,fr);
ffoa(num11,num12,num21,num22,'/',fl,fr);
return 0;
}
long long gcd(long long a, long long b)
{
long long res=a%b;
while(res){
a=b;
b=res;
res=a%b;
}
return b;
}
void getFraction(long long num1,long long num2,fraction& f)
{
if(num2==0){ f.inf=true; return;}
if(num1<0) { //若为负数,则记录符号 转化成正数计算
f.symbol='-';
num1=-num1;
}
f.inte=num1/num2; //转换成带分数形式
num1=num1%num2;
long long comDiv=0;
if(num1){ //若分子不为0
comDiv=gcd(num1,num2); //求出最大公约数
num1/=comDiv;
num2/=comDiv;
f.numerator=num1;
f.denominator=num2;
}
else { f.numerator=0;f.denominator=num2;}
}
void printFraction(const fraction& f1)
{
if(f1.inf) { printf("Inf"); return;}
if(f1.symbol=='-') printf("(-");
if(f1.inte||f1.numerator){ //整数部分和分子至少一个不为0
if(f1.inte){
printf("%lld",f1.inte);
if(f1.numerator) printf(" ");
}
if(f1.numerator) printf("%lld/%lld",f1.numerator,f1.denominator);
}
else printf("0");
if(f1.symbol=='-') printf(")");
}
void ffoa(long long n11,long long n12,long long n21,long long n22,const char op,const fraction& p1,const fraction& p2)
{
fraction answer;
long long num1,num2; //储存计算后的分式的分子和分母
switch(op){
case '+': { num1=n11*n22+n21*+n12; num2=n12*n22;break;}
case '-': { num1=n11*n22-n21*n12; num2=n12*n22;break;}
case '*': { num1=n11*n21; num2=n12*n22; break;}
default: {
num1=n11*n22; num2=n21*n12;
if(num2<0){ num1=-num1;num2=-num2;} //若分母小于0,说明分子的负号串位了
break;
}
}
getFraction(num1,num2,answer);
printFraction(p1); printf(" %c ",op); printFraction(p2);
printf(" = "); printFraction(answer);printf("\n");
}
最后,贴上找到的别人写的简洁不少的实现的链接(30来行的代码)
链接:https://www.liuchuo.net/archives/492