大整数阶乘程序设计_B09040121
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
程序设计报告
( 2010 / 2011学年第一学期)题目:大整数阶乘
专业计算机科学与技术学生姓名张赛
班级学号B09040121
指导教师杨一涛
指导单位计算机学院
日期2010.9.30
大整数阶乘
一、课题内容和要求
1、系统的基本功能及要求
(1)写一个类BigInteger,并有如下成员函数operator+/ operator-/ operator*/ operator\,即整数的四则运算并重载运算符。
(2)用该大整数计算n的阶乘并显示出来。
(n∈[1,100])
注:为了简化,可不考虑负数,则遇上形如“2-4”这样的表达式需要报错。
2、程序执行过程
(1)系统从键盘读入自然数n,直到输入了合法的n为止。
(2)输出运算的结果,为便于观察结果,每输出四位中间插入空格,格式如下(例如,n=12):12!= 4790 0160 0
(3)询问用户是否继续进行,用户选择“是”,直到输入合法为止,转(1),否则退出程序。
3、算法要求及提示
(1)因为n较大时,n!的结果将超出长整形的保存范围,因此结果不能用long int型的变量来保存。
本算法要求用链表来存储。
(2)链表的每一个节点存储结果的一位数字,因此结果的输出实际上是链表的遍历问题,同时要先考虑用多少位来表示大整数。
4、其他要求
(1)输入时具备一定的容错性判断,如输入的不是数字,或输入的数超过范围等等。
(2)变量、函数命名符合规范。
(3)注释详细:每个变量都要求有注释说明用途;函数有注释说明功能,对参
数、返回值也要以注释的形式说明用途;关键的语句段要求有注释解释。
(4)程序的层次清晰,可读性强。
二、需求分析
1)课题要求已说明结果不能用long int型的变量来保存,要求用链表来存储。
,首先要定义一个节点类,在这里定义一个双向节点类。
2)定义一个BigInteger大整数类,使其能够存放大数阶乘,并实现其的四则运算。
3)对输入整数的合法性进行检查,必须考虑用户各种输入情况。
三.概要设计
1.使用单链表存储数据,结点类定义如下:
class Node
{
int data;
Node* next;//指向大数的高位
Node* pre;//指向大数的低位
friend class BigInteger;
};
2.使用大整数类来进行大整数四则算法的重载,在主函数中通过定义大整数对象调用,大整数类定义如下:
class BigInteger//定义大整数类
{
public:
Node *head,*head1;
int n,temp,i,jinwei;
BigInteger();//无参构造函数
~BigInteger();//析构函数
void jiecheng();//阶乘函数
void operator +( BigInteger p1);//加法运算重载声明
void operator -( BigInteger p1);//减法运算重载声明
void operator *( BigInteger p1);//乘法运算重载声明
void operator /( BigInteger p1);//除法运算重载声明
};
3.算法设计说明:
因为n较大时,n!的结果将超出长整形的保存范围,因此结果不能用long int 型的变量来保存。
本算法数据用单链表来存储。
链表的每一个节点存储结果的一位数字,因此结果的输出实际上是链表的遍历问题,同时要先考虑用多少位来表示大整数。
首先申请一个结点类并赋数据域初值1,然后遍历单链表逐个的数据域与i(1到n)相乘;
乘完后重新遍历,对每个结点的数据域处理,若小于10则跳过;
否则,判断下一结点是否存在,若存在则该数据域除10取余,下一结点的数据域加上该数据域除10的结果,若不存在则申请新结点空间,处理同上;
全部乘完并处理完后,遍历单链表并输出各自的数据域即可,注意每四个输出一个空格。
4、流程图
四.详细设计
1.阶乘函数作为BigInteger类中的函数,在主函数通过定义大整数类对象调用,阶乘函数的定义如下:
void BigInteger::jiecheng()
{
Node *cur,*cc;
Node *head=new Node;//存放第一个节点,值为1
head->data=1;
head->pre=head->next=NULL;
for(i=2;i<=n;i++)//从2开始连乘到n
{
cur=head;
jinwei=0;
while(1)
{
temp=i*(cur->data)+jinwei;
cur->data=temp%10;//取个位存下来,如91*2=182,取2存储
jinwei=temp/10;//十位和百位作为进位,取18为进位
if(cur->next==NULL)
break;
cur=cur->next;
}
while(jinwei!=0)//如果乘完一个i发现还有进位,就必须新增结点,由于进位可能是多位数,所以必须用//while
{
cc=new Node;
cc->data=jinwei%10;
cc->pre=cur;
cc->next=NULL;
cur->next=cc;
cur=cc;
jinwei/=10;
}
}
cout<<n<<"!= ";
cur=head,i=0;
while(cur->next)cur=cur->next;//遍历到最高位while(cur)//从最高位到最低位打印
{
cc=cur;
if(i==4)
{
i=0;
cout<<' ';
}
cout<<cur->data;
cur=cur->pre;
i++;
delete cc;
}
}
2.阶乘加法函数的重载定义:
void BigInteger::operator +( BigInteger p1) {
Node *cur,*cc,*cur1,*cc1;
head=new Node;//存放第一个节点,值为1
head->data=1;
head->pre=head->next=NULL;
for(i=2;i<=n;i++)//从2开始连乘到n
{
cur=head;
jinwei=0;
while(1)
{
temp=i*(cur->data)+jinwei;
cur->data=temp%10;//取个位存下来,如91*2=182,取2存储
jinwei=temp/10;//十位和百位作为进位,取18为进位
if(cur->next==NULL)
break;
cur=cur->next;
}
while(jinwei!=0)//如果乘完一个i发现还有进位,就必须新增结点,由于进位可能是多位数,所以必须用
//while
{
cc=new Node;
cc->data=jinwei%10;
cc->pre=cur;
cc->next=NULL;
cur->next=cc;
cur=cc;
jinwei/=10;
}
}
head1=new Node;//存放第一个节点,值为1
head1->data=1;
head1->pre=head1->next=NULL;
for(i=2;i<=p1.n;i++)//从2开始连乘到n
{
cur1=head1;
jinwei=0;
while(1)
{
temp=i*(cur1->data)+jinwei;
cur1->data=temp%10;//取个位存下来,如91*2=182,取2存储
jinwei=temp/10;//十位和百位作为进位,取18为进位
if(cur1->next==NULL)
break;
cur1=cur1->next;
}
while(jinwei!=0)//如果乘完一个i发现还有进位,就必须新增结点,由于进位可能是多位数,所以必须用
//while
{
cc1=new Node;
cc1->data=jinwei%10;
cc1->pre=cur1;
cc1->next=NULL;
cur1->next=cc1;
cur1=cc1;
jinwei/=10;
}
}
if(n>p1.n)//若this.n大于等于p1.n
{
cur=head;
cur1=head1;
while(cur&&cur1)//同时遍历两个单链表,其中有一个结束就停止遍历
{
cur->data+=cur1->data;//cur的数据域等于cur的数据域与cur1的数据域的和
cur=cur->next;
cur1=cur1->next;
}
cur=head;//cur指向头结点
do//利用阶乘函数中的算法处理单链表各个节点的数据域
{
if(cur->data<10)
continue;
if(cur->data>=10)
{
if(cur->next)
{ cur->next->data+=cur->data/10;
cur->data=cur->data%10;
}
else
{
Node *q=new Node;
q->next=cur->next;
cur->next=q;
q->data+=cur->data/10;
cur->data=cur->data%10;
}
}
}while(cur=cur->next);
cur=head,i=0;
while(cur->next)cur=cur->next;//遍历到最高位
while(cur)//从最高位到最低位打印
{
cc=cur;
if(i==4) //每输出四个空一格
{
i=0;
cout<<' ';
}
cout<<cur->data;
cur=cur->pre;
i++;
delete cc;
}
}
else
{
cur=head;
cur1=head1;
while(cur&&cur1)//同时遍历两个单链表,其中有一个结束就停止遍历
{
cur1->data+=cur->data;//cur1的数据域等于cur1的数据域与m的数据域的和
cur1=cur1->next;
cur=cur->next;
}
cur1=head1;
do//利用阶乘函数中的算法处理单链表各个节点的数据域{
if(cur1->data<10)
continue;
if(cur1->data>=10)
{
if(cur1->next)
{
cur1->next->data+=cur1->data/10;
cur1->data=cur1->data%10;
}
else
{
Node *q=new Node;
q->data=0;
q->next=cur1->next;
cur1->next=q;
q->pre=cur1;
q->data+=cur1->data/10;
cur1->data=cur1->data%10;
}
}
}while(cur1=cur1->next);
cur1=head1,i=0;
while(cur1->next)cur1=cur1->next;//遍历到最高位
while(cur1)//从最高位到最低位打印
{
cc=cur1;
if(i==4) //每输出四个空一格
{
i=0;
cout<<' ';
}
cout<<cur1->data;
cur1=cur1->pre;
i++; delete cc;
}
}
}
3.阶乘减法函数的重载定义:
void BigInteger::operator -( BigInteger p1)
{
if(n==p1.n)//若this.n等于p1.n
{
cout<<"0";
}
else//若this.n不等于p1.n
{
Node *cur,*cc,*cur1,*cc1;
head=new Node;//存放第一个节点,值为1
head->data=1;
head->pre=head->next=NULL;
for(i=2;i<=n;i++)//从2开始连乘到n
{
cur=head;
jinwei=0;
while(1)
{
temp=i*(cur->data)+jinwei;
cur->data=temp%10;//取个位存下来,如91*2=182,取2存储
jinwei=temp/10;//十位和百位作为进位,取18为进位
if(cur->next==NULL)
break;
cur=cur->next;
}
while(jinwei!=0)//如果乘完一个i发现还有进位,就必须新增结点,由于进位可能是多位数,所以必须用
//while
{
cc=new Node;
cc->data=jinwei%10;
cc->pre=cur;
cc->next=NULL;
cur->next=cc;
cur=cc;
jinwei/=10;
}
}
head1=new Node;//存放第一个节点,值为1
head1->data=1;
head1->pre=head1->next=NULL;
for(i=2;i<=p1.n;i++)//从2开始连乘到n
{
cur1=head1;
jinwei=0;
while(1)
{
temp=i*(cur1->data)+jinwei;
cur1->data=temp%10;//取个位存下来,如91*2=182,取2存储
jinwei=temp/10;//十位和百位作为进位,取18为进位
if(cur1->next==NULL)
break;
cur1=cur1->next;
}
while(jinwei!=0)//如果乘完一个i发现还有进位,就必须新增结点,由于进位可能是多位数,所以必须用
//while
{
cc1=new Node;
cc1->data=jinwei%10;
cc1->pre=cur1;
cc1->next=NULL;
cur1->next=cc1;
cur1=cc1;
jinwei/=10;
}
}
if(n>p1.n)//若this.n大于p1.n
{
cur=head;
cur1=head1;
while(cur&&cur1)//同时遍历两个单链表,其中有一个结束就停止遍历{
cur->data-=cur1->data;
cur=cur->next;
cur1=cur1->next;
}
cur=head;
do//遍历单链表
{
if(cur->data<0)//若p的数据域小于0
{
cur->next->data-=1;//p的后继结点的数据域减1
cur->data+=10;//p的数据域加10
}
}while(cur=cur->next);
cur=head,i=0;
while(cur->next)cur=cur->next;//遍历到最高位
while(cur)//从最高位到最低位打印
{
cc=cur;
if(i==4) //每输出四个空一格
{
i=0;
cout<<' ';
}
cout<<cur->data;
cur=cur->pre;
i++;
delete cc;
}
}
else
{
cur=head;
cur1=head1;
while(cur&&cur1)//同时遍历两个单链表,其中有一个结束就停止遍历{
cur1->data-=cur->data;
cur1=cur1->next;
cur=cur->next;
}
cur1=head1;
do//遍历单链表
{
if(cur1->data<0&&cur1->next)//若cur1的数据域小于0
{
cur1->next->data-=1;//cur1的后继结点的数据域减1
cur1->data+=10;//cur1的数据域加10
}
}while(cur1=cur1->next);
cur1=head1,i=0;
while(cur1->next)cur1=cur1->next;//遍历到最高位
cout<<"-";
while(cur1)//从最高位到最低位打印
{
cc1=cur1;
if(i==4) //每输出四个空一格
{
i=0;
cout<<' ';
} cout<<cur1->data;
cur1=cur1->pre;
i++;
delete cc1;
}
}
}
}
4.阶乘乘法函数重载的定义:
void BigInteger::operator *( BigInteger p1)
{
Node *cur,*cur1,*cc,*cc1;
head=new Node;//存放第一个节点,值为1
head->data=1;
head->pre=head->next=NULL;
for(i=2;i<=n;i++)//从2开始连乘到n
{
cur=head;
jinwei=0;
while(1)
{
temp=i*(cur->data)+jinwei;
cur->data=temp%10;//取个位存下来,如91*2=182,取2存储
jinwei=temp/10;//十位和百位作为进位,取18为进位
if(cur->next==NULL)
break;
cur=cur->next;
}
while(jinwei!=0)//如果乘完一个i发现还有进位,就必须新增结点,由于进位可能是多位数,所以必须用
//while
{
cc=new Node;
cc->data=jinwei%10;
cc->pre=cur;
cc->next=NULL;
cur->next=cc;
cur=cc;
jinwei/=10;
}
}
for(i=1;i<=p1.n;i++)//从2开始连乘到n
{
cur1=head;
jinwei=0;
while(1)
{
temp=i*(cur1->data)+jinwei;
cur1->data=temp%10;//取个位存下来,如91*2=182,取2存储
jinwei=temp/10;//十位和百位作为进位,取18为进位
if(cur1->next==NULL)
break;
cur1=cur1->next;
}
while(jinwei!=0)//如果乘完一个i发现还有进位,就必须新增结点,由于进位可能是多位数,所以必须用
//while
{
cc1=new Node;
cc1->data=jinwei%10;
cc1->pre=cur1;
cc1->next=NULL;
cur1->next=cc1;
cur1=cc1;
jinwei/=10;
}
}
cur1=head,i=0;
while(cur1->next)cur1=cur1->next;//遍历到最高位
while(cur1)//从最高位到最低位打印
{
cc1=cur1;
if(i==4) //每输出四个空一格
{
i=0;
cout<<' ';
}
cout<<cur1->data;
cur1=cur1->pre;
i++;
delete cc1;
}
}
5.阶乘除法函数重载的定义:
void BigInteger::operator/(BigInteger p1)
{
if(n==p1.n)//若this.n等于p1.n
{
cout<<"1"<<endl;
}
else
if(n<p1.n)
{
cout<<"0"<<endl;
}
if(n>p1.n)
{
Node *cur,*cc;
head=new Node;//存放第一个节点,值为1
head->data=1;
head->pre=head->next=NULL;
for(i=p1.n+1;i<=n;i++)//从p1.n开始连乘到n
{
cur=head;
jinwei=0;
while(1)
{
temp=i*(cur->data)+jinwei;
cur->data=temp%10;//取个位存下来,如91*2=182,取2存储
jinwei=temp/10;//十位和百位作为进位,取18为进位
if(cur->next==NULL)
break;
cur=cur->next;
}
while(jinwei!=0)//如果乘完一个i发现还有进位,就必须新增结点,由于进位可能是多位数,所以必须用
//while
{
cc=new Node;
cc->data=jinwei%10;
cc->pre=cur;
cc->next=NULL;
cur->next=cc;
cur=cc;
jinwei/=10;
}
}
cur=head,i=0;
while(cur->next)cur=cur->next;//遍历到最高位
while(cur)//从最高位到最低位打印
{
cc=cur;
if(i==4) //每输出四个空一格
{
i=0;
cout<<' ';
}
cout<<cur->data;
cur=cur->pre;
i++; delete cc;
}
}
}
五、数据测试及其结果分析
1.数据测试
测试界面:
输入错误整数:123
输入正确整数:12
接着输入y
接着输入5
接着输入n
接着输入6
接着输入5
2.结果分析:
刚开始运行,程序首先提示用户程序是计算大整数的阶乘及其四则运算的功能,并提示用户按照输入一个自然数;
如果输入的数大于100或小于1,则提示用户输入错误;
若输入正确,则进行阶乘运算,输出结果,然后提示用户是否继续,若继续,则提示用户输入自然数n,继续进行阶乘运算,否则,则以下进入大整数阶乘的四则运算,提示输入第一运算对象的n值;
若输入不正确,则提示用户重新输入,直至正确为止,然后提示用户输入第二运算对象的n值,若输入不正确,则提示用户重新输入,直至正确为止,然后则输出四则运算的结果。
六、调试过程中的问题
1.主函数执行过程中,即便选择了n,程序总提示输入。
While循环中忘了加
break语句,导致while语句一直执行。
2.重载减法运算时,当第一操作数比第二操作数大时,困惑了好一会儿,后来
经过讨论和自己的思考,解决了这个问题,依然拿大的操作数减小的操作数,输出的时候只要在结果前加一个‘-’即可。
3.在阶乘函数中,误将if(cur->next==NULL)写成if(cur ==NULL),导致结果
出错,还是太粗心。
4.主函数中,输出四则运算结果时,由于对重载运算符掌握不是很好,写成
cout<<big1+big2;导致出错,应去掉cout<<。
七、课程设计总结
这次程序设计让我清醒的认识到自己知识上的缺陷与漏洞,对过去学的单链表的操作不是很熟悉,从而让我回归书本,认真看书,回顾了以前所学的单链表的操作,熟悉单链表的使用,不会像以前那样生疏。
这次程序设计也让我了解到合作对编程是多么重要,大家互相讨论,灵感碰撞,有了很多意想不到的收获。
拿到问题要找到核心,找到突破口,只有针对问题认真思考好了之后,再动手编程就会简单得多了,而不能图快,这次的算法核心是阶乘算法,抓准问题的实质,先集中精力突破核心的算法,这样就能极大地提高效率。
还需要进行大量的调试,不能浮躁,要根据调试中出现的问题进行分析,修改需要改动的程序,后期再不断完善。
总之,这次程序设计让我受益匪浅,让我清醒的认识到了不足与差距,也给了我很大的动力,对我编程能力也有较大的提升,我相信通过努力我一定也会成功的。