目录
一、题目
二、代码
三、算法分析
(一)数学表达式
(二) 代码实现
一)+运算符重载函数
二)优化函数(实现有理数约分)
一、题目
通过运算符重载为类的成员函数来实现两个有理数对象的加减乘除运算;
有理数是一个可以化为分数的数,如2/3,533/920,都是有理数,而根号2、Π等就为无理数。
在C++中,并没有预先定义有理数,需要时可以声明一个有理数类,将有理数的分子和分母分别存放在nume和deno变量中,对有理数的各种操作都可以用重载运算符来实现。可以写一个优化函数optimize,它的作用时使有理数约去公分母,也就是说,使保存的有理数分子和分母之间没有公约数(除1以外)。在创建有理数对象时才能执行它,在执行各种运算之后也能执行它,从而保证所存储的有理数都是最优的。
二、代码
#include<iostream>
using namespace std;
#include<cmath>
class Rational //定义有理数类
{
public:
Rational(int x=0,int y=1); //类的构造函数
void print(); //打印出有理数
Rational operator+(Rational a); //类的运算符重载函数(成员函数),实现有理数加法
private:
int nume; //分子
int deno; //分母
void optimize(); //优化函数,实现对有理数的约分
};
void Rational::optimize() //优化函数,实现对有理数的约分
{
int gcd,i; //gcd存放分子和分母较大的一个,i记录更新的公约数
if(nume==0) //①如果分子为0,则分母置1,返回,约分结束
{
deno=1;
return;
}
//②分子不为0,继续约分操作
gcd=(abs(nume)>abs(deno)?abs(nume):abs(deno)); //gcd为分子和分母中较大的一个
if(gcd==0) //若为0,则无需约分,返回,结束约分操作
return ;
for(i=gcd;i>1;i--) //for循环,从gcd开始,逐次-1,判断是否为公约数,找到一个即返回(最大公约数)
{
if((nume%i==0)&&(deno%i)==0) //判断是否为公约数
break;
}
nume/=i; //根据找到的最大公约数,更新分子和分母
deno/=i;
if(nume<0&&deno<0) //若分子分母同为负数,则结果为正,所以均改为正
{
nume=-nume;
deno=-deno;
}
else if(nume<0||deno<0) //若分子分母中有一个为负,则结果为负,分子调整为负,分母调整为正
{
nume=-abs(nume);
deno=abs(deno);
}
}
Rational::Rational(int x,int y) //构造函数的定义,同时调用优化函数,对有理数继续约分
{
nume=x;
deno=y;
optimize();
}
void Rational::print() //打印有理数
{
cout<<nume;
if(nume!=NULL) //①分子不为0
cout<<"/"<<deno<<endl;
else //②分子为0
cout<<endl;
}
//函数返回的不是引用类型,因为不可以作为左值
Rational Rational::operator+(Rational a) //+运算符重载函数,实现类(用户自定义的数据类型)的加法运算
{
Rational r; //定义一个临时变量,自动调用类的构造函数,占有栈区,程序结束后系统自动调用析构函数,释放内存
r.deno=a.deno*deno;
r.nume=a.nume*deno+a.deno*nume;
r.optimize(); //运算完也需要约分
return r;
}
int main()
{
Rational r1(3,14),r2(4,14),r3;
r1.print();
r2.print();
r3=r1+r2;
r3.print();
return 0;
}
三、算法分析
有理数相加
(一)数学表达式
当两个有理数 和相加时,可得到这样的算式
分子分母分开存放
分子=a*d+b*c
分母=b*d
运算完毕后,需要对词有理数继续优化,
此操作可通过重载运算符“+”实现。
(二) 代码实现
一)+运算符重载函数
代码
Rational Rational::operator+(Rational a) //+运算符重载函数,实现类(用户自定义的数据类型)的加法运算
{
Rational r; //定义一个临时变量,自动调用类的构造函数,占有栈区,程序结束后系统自动调用析构函数,释放内存
r.deno=a.deno*deno;
r.nume=a.nume*deno+a.deno*nume;
r.optimize(); //运算完也需要约分
return r;
}
分析
重载了运算符后,在进行有理数运算时,只需像基本类型的运算一样书写即可,这样给用户带来了很大的方便,并且很直观。
r3=r1+r2;
执行时,C++可以解释为
r3=r1.operator+(r2);
由此可以看出,C++系统在处理算术表达式“r1+r2”时,把对表达式的处理自动转化为对成员运算符重载函数operator+的调用(r1.operator+(r2)),通过“+”运算符左边的对象去调用operator+,“+”右边的对象作为函数调用的实参。
这样双目运算符左边的对象就由系统通过this指针隐含地传递给operator+函数。因此,如果将双目运算符函数重载为类的成员函数,其参数表只需写一个形参就可以了。
但必须要求运算表达式第一个参数(运算符左边的操作数)是一个类对象。而且与运算符函数的返回类型相同。这是因为必须通过类的对象去调用该类的成员函数,而且只要运算符重载函数返回值与改对象同类型,运算才有意义。
二)优化函数(实现有理数约分)
代码
void Rational::optimize() //优化函数,实现对有理数的约分
{
int gcd,i; //gcd存放分子和分母较大的一个,i记录更新的公约数
if(nume==0) //①如果分子为0,则分母置1,返回,约分结束
{
deno=1;
return;
}
//②分子不为0,继续约分操作
gcd=(abs(nume)>abs(deno)?abs(nume):abs(deno)); //gcd为分子和分母中较大的一个
if(gcd==0) //若为0,则无需约分,返回,结束约分操作
return ;
for(i=gcd;i>1;i--) //for循环,从gcd开始,逐次-1,判断是否为公约数,找到一个即返回(最大公约数)
{
if((nume%i==0)&&(deno%i)==0) //判断是否为公约数
break;
}
nume/=i; //根据找到的最大公约数,更新分子和分母
deno/=i;
if(nume<0&&deno<0) //若分子分母同为负数,则结果为正,所以均改为正
{
nume=-nume;
deno=-deno;
}
else if(nume<0||deno<0) //若分子分母中有一个为负,则结果为负,分子调整为负,分母调整为正
{
nume=-abs(nume);
deno=abs(deno);
}
}
分析
寻找最大公约数的步骤
①初始最大公约数gcd
gcd=(abs(nume)>abs(deno)?abs(nume):abs(deno)); //gcd为分子和分母中较大的一个
② 判断是否为公约数
for(i=gcd;i>1;i--) //for循环,从gcd开始,逐次-1,判断是否为公约数,找到一个即返回(最大公约数)
{
if((nume%i==0)&&(deno%i)==0) //判断是否为公约数
break;
}