长整数四则运算加减法.docx
《长整数四则运算加减法.docx》由会员分享,可在线阅读,更多相关《长整数四则运算加减法.docx(23页珍藏版)》请在冰豆网上搜索。
长整数四则运算加减法
青岛理工大学
数据结构课程设计报告
题目:
长整数四则运算
院(系):
计算机工程学院
学生姓名:
班级:
学号:
起迄日期:
指导教师:
房斐斐
2012—2013年度第2学期
一、需求分析
1.问题描述:
设计一个实现任意长的整数进行加、减法运算的演示程序。
2.基本功能
1、本程序实现计算任意长的整数的加、减法运算.以用户和计算机对话的方式,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入演示程序中规定的运算命令,然后程序就计算并显示出这两个数的运算。
2、本演示程序中,集合的元素限定为数字字符[‘0’~’9’]和字符‘,’与‘;’,输入字符可以任意长,输入形式以“回车符”为结束标志,串中字符顺序不限,且允许出现重复字符。
3、利用双向循环链表现实长整数的存储,每个结点含一个整形变量。
输入的形式以回车结束,可以直接输入正数或负数。
按中国对于长整数的表示习惯,每四位一组,除数字和位于首位置的负号外,其它一切字符都将作为分隔符,连续多个分隔符当一个处理。
但不使用分隔符也不影响结果。
3.输入输出
(1)0;0;加法应输出“0”,减法应输出”0”。
(2)-2345,6789;-7654,3211;加法应输出“-1,0000,0000”,减法应输出”5408,6422”。
(3)-9999,9999;1,0000,0000,0000;加法应输出“9999,0000,0001”,减法应输出1,0000,9999,9999。
(4)1,0001,0001;-1,0001,0001;加法应输出“0”,减法应输出”2,0002,0002”。
(5)1,0001,0001;-1,0001,0000;加法应输出“1”,减法应输出”2,0002,0001”。
(6)-9999,9999,9999;-9999,9999,9999;加法应输出“1,9999,9999,9998”,减法应输出”0”。
(7)1,0000,9999,9999;1;加法应输出“1,0001,0000,0000”,减法应输出”1,0000,9999,9998”。
二、概要设计
1.设计思路:
(1)利用双向循环链表现实长整数的存储,每个结点中可以存放的最大整数为32767,才能保证两数相加不会溢出,但若这样存放,即相当于按32768进制存放,在十进制与32768进制数之间的转换十分不方便,故可以在每个结点中仅存十进制的4位,即不超过9999的非负整数,整个链表表示为万进制。
(2)可以利用头结点数据域的符号代表长整数的符号。
用其绝对值表示元素结点数目。
相加过程中不要破坏两个操作数链表。
两操作数的头指针存于指针数组中是简化程序结构的一种方法。
不能给长整数位数规定上限。
2.数据结构设计:
1)数据类型:
typedefintDataType;//定义数据类型
typedefstructDoubleNode//定义链表元素
{
DataTypedata;
structDoubleNode*prior;
structDoubleNode*next;
}DLNode;
2)存储结构:
顺序结构,链式存储。
采用链式存储的方式会方便字符的读入和操作,且算法简单易懂。
3.软件结构设计:
1)初始化链表
voidInitNode(DLNode**head)
2)向链表第n个位置插入元素X
intInsertNode(DLNode*head,intn,DataTypex)
3)判断整数N有几位
intdigit(intn)
4)两数相加
voidadd(DLNode*h1,DLNode*h2)
5)两数相减
voidjian(DLNode*h1,DLNode*h2)
6)打印链表
voidPrintNode(DLNode*head)
7)删除链表
voidDestroyNode(DLNode**head)
8)主函数
intmain()
三、详细设计
数据类型。
typedefintDataType;//定义数据类型
typedefstructDoubleNode//定义链表元素
{
DataTypedata;
structDoubleNode*prior;
structDoubleNode*next;
}DLNode;
2.存储结构类型:
voidInitNode(DLNode**head)//初始化链表
{
if((*head=(DLNode*)malloc(sizeof(DLNode)))==NULL)
exit
(1);
(*head)->prior=*head;
(*head)->next=*head;
}
3.主函数和其他函数的伪码算法;
1.主函数:
intmain()//主函数
{
DLNode*head1,*head2;
chardata1[N],data2[N];
chard1[10],d2[10];
inti,j,k;
intxun;
printf("提示:
较长的字符串数作为被加数,如果等长,则第一个数加第二个数\n\n");
while
(1)
{
printf("输入数据:
\n");
scanf("%s%s",data1,data2);
InitNode(&head1);
InitNode(&head2);
i=0;
k=0;
while(data1[i]!
=';')//将数1用链表储存
{
for(j=0;j<10;j++)
d1[j]=0;
j=0;
while(data1[i]!
=';'&&data1[i]!
=',')
d1[j++]=data1[i++];
if(data1[i]==',')
i++;
if(data1[0]=='-')//处理正负数
j=-(int)fabs(atoi(d1));//atoi()把字符串转换成整型数,头文件:
#include
else
j=atoi(d1);
InsertNode(head1,k++,j);
}
i=0;
k=0;
while(data2[i]!
=';')//将数2用链表储存
{
for(j=0;j<10;j++)
d2[j]=0;
j=0;
while(data2[i]!
=';'&&data2[i]!
=',')
d2[j++]=data2[i++];
if(data2[i]==',')
i++;
if(data2[0]=='-')//处理正负数
j=-(int)fabs(atoi(d2));
else
j=atoi(d2);
InsertNode(head2,k++,j);
}
printf("选择加减法:
1—加法,0—退出\n");
scanf("%d",&xun);
if(xun==0)
break;
switch(xun)
{
case1:
if(strlen(data1)>=strlen(data2))//较长的数作为被加数
add(head1,head2);
elseadd(head2,head1);
break;
default:
break;
}
DestroyNode(&head1);
DestroyNode(&head2);
printf("\n\n");
}
return0;
}
2.初始化链表:
voidInitNode(DLNode**head)//初始化链表
{
if((*head=(DLNode*)malloc(sizeof(DLNode)))==NULL)
exit
(1);
(*head)->prior=*head;
(*head)->next=*head;
}
3.向链表第n个位置插入元素X
intInsertNode(DLNode*head,intn,DataTypex)//向链表第n个位置插入元素X
{
DLNode*p,*nt;
inti=0;
p=head->next;
while(p!
=head&&i{
p=p->next;
i++;
}
if(i!
=n)
{
printf("插入位置错误\n");
return0;
}
if((nt=(DLNode*)malloc(sizeof(DLNode)))==NULL)
exit
(1);
nt->data=x;
nt->prior=p->prior;
nt->prior->next=nt;
nt->next=p;
p->prior=nt;
return1;
}
4.判断整数N有几位
intdigit(intn)//判断整数N有几位
{
inti;
for(i=1;;n/=10,i++)
{
if(n/10==0)
returni;
}
}
5.打印链表
voidPrintNode(DLNode*head)//打印链表
{
printf("结果是:
");
DLNode*p=head->prior;
inti;
while(p->data==0)//去掉前面的一串0
{
p=p->prior;
if(p==head)
{
printf("0\n");
return;
}
}
printf("%d",p->data);//最前面的一个数进行特殊处理,不用补零
p=p->prior;
while(p!
=head)//打印后面的数字
{
printf(",");
if(p->data==0)
{
printf("0000");
p=p->prior;
continue;
}
for(i=0;i<4-digit(p->data);i++)//补零
printf("0");
printf("%d",p->data);
p=p->prior;
}
printf("\n");
}
6.删除链表
voidDestroyNode(DLNode**head)
{
DLNode*p,*p1;
p=(*head)->next;
while(p!
=*head)
{
p1=p;
p=p->next;
free(p1);
}
free(p);
head=NULL;
}
7.两数相加
voidadd(DLNode*h1,DLNode*h2)
{
inti=0,j=0;
DLNode*head3;
InitNode(&head3);
DLNode*p1=h1->prior,*p2=h2->prior,*p3;
while(p1!
=h1&&p2!
=h2)//每个链表元素相加
{
i=p1->data+p2->data;
p1=p1->prior;
p2=p2->prior;
InsertNode(head3,j++,i);
}
while(p1!
=h1)
{
InsertNode(head3,j++,p1->data);
p1=p1->prior;
}
p3=head3->next;
while(p3!
=head3->prior)//处理链表元素
{
if(p3->data>=10000)
{
p3->next->data+=p3->data/10000;
p3->data%=10000;
}
if(p3->data<0)//处理负数
{
if(head3->prior!
=0)
{
p3->next->data-=1;
p3->data+=10000;
}
p3->data=(int)fabs(p3->data);
}
p3=p3->next;
}
if(head3->prior->data>=10000)//处理最前面的数
{
InsertNode(head3,j,head3->prior->data/10000);
head3->prior->prior->data%=10000;
}
if(head3->prior->data<=-10000)
{
InsertNode(head3,j,head3->prior->data/10000);
head3->prior->prior->data%=10000;
head3->prior->prior->data=(int)fabs(head3->prior->prior->data);
}
PrintNode(head3);
}
8.两数相减
voidjian(DLNode*h1,DLNode*h2)
{
inti=0,j=0;
DLNode*head4;
InitNode(&head4);
DLNode*p1=h1->prior,*p2=h2->prior,*p4;
while(p1!
=h1&&p2!
=h2)//每个链表元素相减
{
i=p1->data-p2->data;
p1=p1->prior;
p2=p2->prior;
InsertNode(head4,j++,i);
}
while(p1!
=h1)
{
InsertNode(head4,j++,p1->data);
p1=p1->prior;
}
p4=head4->next;
while(p4!
=head4->prior)//处理链表元素
{
if(p4->data>=10000)
{
p4->next->data+=p4->data/10000;
p4->data%=10000;
}
if(p4->data<0)//处理负数
{
if(head4->prior!
=0&&p4->data<=-10000)
{
p4->next->data-=1;
p4->data+=10000;
}
p4->data=(int)fabs(p4->data);
}
p4=p4->next;
}
if(head4->prior->data>=10000)//处理最前面的数
{
InsertNode(head4,j,head4->prior->data/10000);
head4->prior->prior->data%=10000;
}
if(head4->prior->data<=-10000)
{
InsertNode(head4,j,head4->prior->data/10000);
head4->prior->prior->data%=10000;
head4->prior->prior->data=(int)fabs(head4->prior->prior->data);
}
PrintNode(head4);
}
4.主函数的程序流程图
四、调试分析
1.实际完成的情况说明
程序基本功已完成,包括:
输入长整型数字字符,用双向循环链表储存,计算两数之和、之差,输出值,删除链表,基本符合题目要求。
2.程序的性能分析
时间复杂度:
O(strlen(data1)+strlen(data2))
3.上机过程中出现的问题及其解决方案
1)双向循环链表指针指向错误
双向循环链表使用错误,指针顺序不对,参考教课书改正。
2)打印顺序错误
由于计算值储存顺序是从尾到头,开始误认为是从头到尾,修改指针指向改正。
3)中间计算值错误
中间计算值不足四位的应用0补足。
4)中间值小于0处理错误
中间值小于0但大于-100000的数应取绝对值,小于-10000的数应先借位,这个数加上10000后,再取绝对值
4.程序中可以改进的地方说明
两操作数的头指针存于指针数组中是简化程序结构的一种方法,但由于广泛使用指针易造成混乱,所以就放弃了,以后可以改进。
5.程序中可以扩充的功能及设计实现假想。
本程序可拓展到乘除运算,还有乘方和阶乘运算。
五、测试结果
●测试方法:
输入数据
●测试数据:
(1)0;0;加法应输出“0”,减法应输出”0”。
(2)-2345,6789;-7654,3211;加法应输出“-1,0000,0000”,减法应输出”5408,6422”。
(3)-9999,9999;1,0000,0000,0000;加法应输出“9999,0000,0001”,减法应输出1,0000,9999,9999。
(4)1,0001,0001;-1,0001,0001;加法应输出“0”,减法应输出”2,0002,0002”。
(5)1,0001,0001;-1,0001,0000;加法应输出“1”,减法应输出”2,0002,0001”。
(6)-9999,9999,9999;-9999,9999,9999;加法应输出“1,9999,9999,9998”,减法应输出”0”。
(7)1,0000,9999,9999;1;加法应输出“1,0001,0000,0000”,减法应输出”1,0000,9999,9998”。
六、用户手册
本程序使用起来简单方便,只要按照菜单提示进行即可。
1.加法
1.输入0;0;
2.输入-2345,6789;-7654,3211;
3.输入-9999,9999;1,0000,0000,0000;
4.输入1,0001,0001;-1,0001,0001;
5.输入1,0001,0001;-1,0001,0000;
6.输入-9999,9999,9999;-9999,9999,9999;
7.输入1,0000,9999,9999;1;
2.减法
1.输入0;0;
2.输入-2345,6789;-7654,3211;
3.输入-9999,9999;1,0000,0000,0000;
4.输入1,0001,0001;-1,0001,0001;
5.输入1,0001,0001;-1,0001,0000;
6.输入-9999,9999,9999;-9999,9999,9999;
7.输入1,0000,9999,9999;1;
8.输入0;0;后输入0退出
七、体会与自我评价
通过这次的课程设计,我进一步加深了对数据结构的理解。
这次课程设计我抽到的题目是长整数四则运算,长整数四则运算的功能比较单一,即输入两个长整数(数字字符和“,”和“;”),每四个数字字符通过atoi()函数转换成数字后储存在一个节点里,每两个对应的节点相加、相减后,生成一个新的节点来储存,然后对链表进行处理,可采用双向循环链表实现长整数的存储,主要原因是顺序表操作起来比较简单,算法较易理解,然后打印链表,最后删除链表,销毁头结点。
这次的课程设计我采用的是C语言编程语言,在编程过程中也遇到了很多问题,但经过努力调试修改,基本实现了长整数加法的基本功能。
通过这次课程设计我回顾了以前所学的编程知识,理解了学习完数据结构后的编程与以前编程方法上的不同。
在以往的编程方法上,我们习惯于是用数组和顺序的储存结构进行编程,这种方法在进行插入和删除是及为复杂不易实现。
但数据结构给我们提供了更多的不同的而且较为简单的编程方法,如链表,而且通过这次课程设计,我认识到了链表的许多优点。
通过这次编程我还学习到了一些新的知识,现如下总结:
1)把字符串转换成整型数函数:
atoi()函数,它包含在头文件:
#include中。
2)双向循环链表的使用,使我对链表的储存结构有了全新的认识
3)再进行数据处理时应仔细分析
4)应仔细分析运算法则