数据结构实验.docx
《数据结构实验.docx》由会员分享,可在线阅读,更多相关《数据结构实验.docx(14页珍藏版)》请在冰豆网上搜索。
数据结构实验
中南民族大学管理学院
学生实验报告
实验项目:
长整型的运算
课程名称:
数据结构
年级:
2009
专业:
信息管理与信息系统
************
实验地点:
管理学院综合实验室
完成日期:
2010年11月18日
小组成员:
赵纯龑09056045
数据结构实验报告
-----长整数的运算
一.实验目的
1.利用双向循环链表实现长整数的存储。
2.掌握长整数的运算的表式和实现。
3.学会分析问题,设计适当的解决方案。
二.实验内容
【问题描述】
设计一个实现任意长的整数进行加法运算的演示程序。
【基本要求】
利用双向循环链表实现长整数的存储,每个结点含一个整型变量。
任何整型变量的范围是-(215-1)~~(215-1)。
输入和输出形式:
按中国对长整数的表示习惯,每四位一组,组间用豆号隔开。
【测试数据】
(1)0;0;应输出“0”。
(2)-23456789;-76543211;应输出“-100000000”。
(3)-99999999;1000000000000;应输出“999900000001”。
(4)100010001;-100010001;应输出“0”。
(5)100010001;-100010000;应输出“1”。
(6)-999999999999;-999999999999;应输出“-199999999998”。
(7)1000099999999;1;应输出“1000100000000.
【实验提示】
(1)每个结点中可以存放的最大整数为215-1=32767,才能保证两数据想家不会溢出。
但若这样存放,即相当于按32768进制存放,在十进制与32768进制之间的准话十分不方便。
姑可以在每个结点中仅存十进制的4位,即不超过9999的非负整数,整个链表为万进制数。
(2)可以利用头结点数据域的符号代表成整数的符号。
相加过程中building要破坏两个操作数据链。
不能给长整数位规定上限。
【选作内容】
(1)实现长整数的四则运算;
(2)实现长整数的乘方和阶乘运算;
(3)整型量范围是-(215-1)~(215-1),其中,n是由程序读入的参量。
输入数据的分组方法可以另行规定。
三.实验步骤
(一).需求分析
1.本程序中采用双向循环链表实现对长整数的存储与运算,每个节点含一个整型变量,每四位一组,组间不用逗号隔开。
2.程序由用户输入数据(长整数可正可负),选择加减运算,计算机计算出结果并反馈。
3.程序由多个函数组成,函数见概要设计。
4.长整数位数为100,可根据需要扩充。
(二).概要分析
本实验采用双向链表实现长整数存储
//---------------线形表的双向链表存储结构------------------
Typedefstruct long_int{
int data;
int over;
structlong_int *pro;
structlong_int *next;
}long_int,;
1.每个节点只存储四位十进制数字,即不超过9999的非负整数。
2.双向链表有头指针,它的data值存储长整数的符号,1为正,-1为负,0代表长整数为0;它的over值存储除头节点节点的个数。
3.其他节点的data值存储四位整数,over存储该四位整数溢出0~~9999范围的情况,一般over>0表示四位数超出9999,over<0表示四位数小于0。
(三).抽象数据
抽象数据类型定义:
ADTlong_int{
数据对象:
长整数l
基本操作:
*creat()
操作结果:
构造一个空的只有头指针的双向循环链表。
Print(head)
初始条件:
head存在。
操作结果:
输出以head为头结点的长整数。
*Insert(head,p)
初始条件:
head存在且p指向一个long_int型节点。
操作结果:
将节点p插到头节点后并返回头指针。
*del(head,p)
初始条件:
head存在且p指向的节点在头节点后。
操作结果:
将头节点后的那个节点从链表里删除、释放p的空间并返回头指针
*get(s)
初始条件:
字符串存有字符格式的长整数。
操作结果:
将以字符串形式存储的长整数转化到双向循环链表中存储并返回头指针。
plus(ahead,bhead)
初始条件:
两个循环链表分别存有两个长整数。
操作结果:
将两个长整数做和并输出结果。
minus(ahead,bhead)
初始条件:
两个循环链表分别存有两个长整数。
操作结果:
用第一个长整数减第二个长整数并输出结果。
}ADTlong_int
还需要包含调用若干库文件:
stdio.h,malloc.h,string.h。
(四).详细设计
1.宏定义及节点定义:
#defineLENsizeof(structlong_int)
structlong_int
{
intdata;
intover;
structlong_int*pro;
structlong_int*next;
};
每个节点只存储四位十进制数字,即不超过9999的非负整数。
双向链表有头指针,它的data值存储长整数的符号,1为正,-1为负,0代表长整数为0;它的over值存储除头节点节点的个数。
其他节点的data值存储四位整数,over存储该四位整数溢出0~~9999范围的情况,一般over>0表示四位数超出9999,over<0表示四位数小于0。
2.生成链表函数:
函数C代码:
structlong_int*creat()
{
structlong_int*head;
head=(structlong_int*)malloc(LEN);
if(head==NULL)
printf("mallocerror!
\n");
else
{
head->data=0;
head->over=0;
head->pro=head;
head->next=head;
}
return(head);
}//creat
3.输出函数设计思路:
先判断长整数的正负,为负时先输出“—”号,然后按节点顺序依次输出,返回到头节点为止,输出前要判断各个节点data值的位数来判断先输出几个0。
函数C代码:
voidprint(structlong_int*head)
{
structlong_int*p;
p=head;
if(head->next==head)
printf("longinterror!
\n");
else
{
if(head->data==-1)
printf("-"); //判断长整数是否为正
p=head->next;
printf("%d",p->data);
p=p->next;
while(p!
=head)
{
//判断各个节点data值的位数来判断先输出几个0
if(p->data>=0&&p->data<10)
printf("000%d",p->data);
if(p->data>=10&&p->data<100)
printf("00%d",p->data);
if(p->data>=100&&p->data<1000)
printf("0%d",p->data);
if(p->data>=1000)
printf("%d",p->data);
p=p->next;
}
printf("\n");
}
}//print
4.插入函数:
函数C代码:
voidinsert(structlong_int*head,structlong_int*p)
{ //将节点插到头节点后
p->next=head->next;
head->next->pro=p;
head->next=p;
p->pro=head;
head->over=head->over+1;
}insert
5.删除函数:
函数C代码:
voiddel(structlong_int*head,structlong_int*p)
{ //删除头节点后的节点
head->next=p->next;
p->next->pro=head;
free(p);
head->over=head->over-1;
}//del
转换函数设计思路:
将长整数的字符形式转化成数字形式,存放到双向循环链表中,先判断长整数若为负,减去
字符串的第一位,将数字部分存到双向循环链表中。
函数C代码:
structlong_int*get(chars[])
{ //将长整数存到双向循环链表
structlong_int*head,*q;
inti,j,l=0;
head=creat();
//判断长整数的符号,并将信息存到头节点中
if(s[0]>'0')
head->data=1;
if(s[0]=='0')
head->data=0;
if(s[0]=='-')
{
l=1;
head->data=-1;
}
j=strlen(s)-1;
for(i=l;i<=j;i++)
s[i]=s[i]-'0';
while(j-l>=3)
{
q=(structlong_int*)malloc(LEN);
q->data=s[j]+s[j-1]*10+s[j-2]*100+s[j-3]*1000;
insert(head,q);
j=j-4;
}
if(j>=l) //当最后几位数的位数不足四位时
{
q=(structlong_int*)malloc(LEN);
q->data=0;
while(l<=j)
{
q->data=q->data*10+s[l];
l++;
}
insert(head,q);
}
return(head);
}//get
6.加法函数设计思路:
先将各位做加减,然后根据所得长整数正负和各结点data值进位或退位计算所得长整数的值并输出。
函数C代码:
voidplus(structlong_int*a,structlong_int*b)
{
structlong_int*m,*n,*p,*chead,*q;
if(a->over==0||b->over==0)
printf("longinterror!
\n");
else
{
m=a->pro;
n=b->pro;
chead=creat();
while(m!
=a&&n!
=b)
{
p=(structlong_int*)malloc(LEN);
p->data=a->data*m->data+b->data*n->data;
insert(chead,p);
m=m->pro;
n=n->pro;
}
while(m!
=a||n!
=b)
{
if(m==a)
{
p=(structlong_int*)malloc(LEN);
p->data=b->data*n->data;
n=n->pro;
insert(chead,p);
}
elseif(n==b)
{
p=(structlong_int*)malloc(LEN);
p->data=a->data*m->data;
m=m->pro;
insert(chead,p);
}
}
p=chead->next;
chead->data=0;
while(p!
=chead)
{
if(p->data>0)
{
chead->data=1;
break;
}
if(p->data<0)
{
chead->data=-1;
break;
}
p=p->next;
}
p=chead->pro;
while(p!
=chead)
{
if(p->next!
=chead)
p->data=p->data*chead->data+p->next->over;
if(p->next==chead)
p->data=p->data*chead->data;
p->over=0;
if(p->data>=10000)
p->over=1;
if(p->data<0)
p->over=-1;
p->data=p->data-p->over*10000;
p=p->pro;
}
p=chead->next;
while(p->data==0&&p->over==0&&p->next!
=chead)
{
q=p;
p=p->next;
del(chead,q);
}
if(p->over>0)
{
q=(structlong_int*)malloc(LEN);
q->data=p->over;
insert(chead,q);
}
}
if(chead->next->data==0)
chead->data=0;
print(chead);
}//plus
6.减法函数设计思路:
将被减数换符号,做加法。
函数C代码:
voidminus(structlong_int*a,structlong_int*b)
{
b->data=(-1)*b->data; //将被减数的符号改变
plus(a,b);
}//minus
(五).调试分析
由于本程序输入时对长整数的格式不加限制,且退进位的语句已经写在加法函数里,所以加法函数过于复杂,但减法函数直接调用加法函数即可。
整体设计思路明朗,使用者操作简便。
调试过程中多次出现进退位的错误,可见条件的限制,语句间的逻辑关系都是本程序设计的关键。
设节点数为n,那么加减法的复杂度为O(n)。
算法多处地方可以合并优化,但要注意逻辑关系。
本程序的设计强化了编程能力,加深了链表存储结构的理解。
(六).测试结果
0;0;加减输出:
0;0;0。
-23456789;-76543211;加减输出:
-100000000;-53086422;53086422。
-99999999;1000000000000;加减输出:
999900000001;-1000099999999;1000099999999。
100010001;-100010001;加减输出:
0;200020002;-200020002。
100010001;-100010000;加减输出:
1;200020001,-200020001。
-999999999999;-999999999999;加减输出:
-1999999999998;0;0。
1000099999999;1;加减输出:
1000100000000;1000099999998;-100099999998。