实验一参考.docx
《实验一参考.docx》由会员分享,可在线阅读,更多相关《实验一参考.docx(29页珍藏版)》请在冰豆网上搜索。
![实验一参考.docx](https://file1.bdocx.com/fileroot1/2022-11/20/38255978-81ff-4e60-90b5-da9a5ebc0633/38255978-81ff-4e60-90b5-da9a5ebc06331.gif)
实验一参考
中南大学
《数据结构与算法》课程实验
实验报告
题目实验一线性表的操作
学生姓名
学生学号
专业班级
完成日期
1.需求分析
此实验要求我们掌握线性表的基本操作,插入、删除、查找,以及线性表合并等运算在顺序存储结构和链接存储结构上的运算。
顺序存储结构指的是用数组方法,链接存储结构指的是用链表方法,并通过对两种方法基本操作的掌握,实现一元n次多项式的加法运算。
输入的形式:
按照提示(比如:
“请输入第一个多项式”、“请输入多项式的项数”、“请输入第n项的系数”、“请输入第n项的指数”等等),先输入多项式的项数,之后顺次输入每一项的系数与指数。
输入值的范围:
项数没有要求,但不能过于巨大;系数取为float型数据,指数取为int型数据,
输出的形式:
按照提示(比如:
“输入的第二个多项式为”、“按降幂排列后多项式为”等等),会输出原输入的多项式和经过排序和合并之后的降幂型多项式。
同时,系数会以保留小数点后两位数字的形式输出;若指数输入时为小数,则输出时会自动截取其整数部分。
程序所能达到的功能:
程序可以对输入的序列紊乱的多项式进行加工,使之按照降幂排列,并合并指数相同的项,之后对两多项式进行加法运算(包括系数为负的加法),最后输出最终的多项式。
测试数据:
正确数据:
输入:
5*X^2+4*X^1和-3*X^2+2*X^0
输出:
2.00*X^2+4.00*X^1+2.00
错误数据:
输入:
-2*X^1.5+4*X^2和3*X^2+4*X^1.6
输出:
7.00*X^2+2.00*X^1
2.概要设计
(1)链接存储结构:
此方法中用到的抽象数据类型为结构体:
structnode
{
floatcoef;
intexpo;
structnode*next;
}link;
主程序中给提示建立第一个多项式,并依次调用create函数、order函数和hebing函数,通过调用print函数输出原多项式和整理过后的新多项式。
同理建立并输出第二个多项式,最后通过调用add函数,将两多项式相加,并调用order函数进行整理,最后调用print函数输出结果多项式。
(2)顺序存储结构
此方法中用到的抽象数据类型为结构体:
structpoly
{
floatcoef;
intexpo;
}dxs[15],dxs1[15],dxs2[30];
主函数中也会给出提示建立第一个多项式,并依次调用create函数和order函数,通过两次调用print函数输出原多项式和整理过后的新多项式。
之后,将多项式保存,然后同理建立第二个多项式,最后调用add函数,将两多项式相加。
调用print函数输出结果多项式。
因为此方法中我将合并函数加到order函数里,所以没有单一的hebing函数模块。
3.详细设计
(1)链接存储结构
此方法中定义了一个结构体类型:
structnode
{
floatcoef;//定义系数为float类型数据
intexpo;//定义指数为int类型数据
structnode*next;
}link;
structnode*create()//定义建立多项式函数,并返回链表头指针
{
structnode*h=NULL,*q,*p;//定义结构体头指针h,标记指针p和q
inti=1,N;//定义多项式的项数N及标记数i
for(;i<=N;i++)
{p=(structnode*)malloc(sizeof(link));//为下一个节点分配空间
scanf("%f",&p->coef);
scanf("%d",&p->expo);
if(i==1){h=p;q=p;}
else
{
q->next=p;
q=p;
}
}
q->next=NULL;
p->next=NULL;
returnh;
}
structnode*order(structnode*h)//定义排序函数,并返回整理后的链表的头指针
{
structnode*p,*q,*t,*h1,*h2;//定义三个结构体标记指针和两个头指针
h1=h;//建立一个新的链表,头指针为h,指向原链表的第一个节点,之后将原链表中的节点一个一个的插入此链表,进行排序
h2=h1->next;//将原来的链表建立成待排序链表
h1->next=NULL;//截断第一个原链表中的节点
while(h2!
=NULL)
{
q=h1;
p=q->next;
t=h2;//从待排序链表中选出一个节点准备插入到新链表中
h2=h2->next;//移动待排序链表的头指针,便于进行下一次挑选
t->next=NULL;
if(t->expo>q->expo)//应插入头指针之前的情况
{
t->next=q;
h1=t;
continue;
}
if(p==NULL&&t->expo<=q->expo)q->next=t;//应插入表尾的情况
while(p!
=NULL)
{
if(t->expo>p->expo)
{
q->next=t;
t->next=p;
break;
}
else
{
q=q->next;
p=p->next;
}
}
if(p==NULL)q->next=t;
}
returnh1;//新链表即为按降幂顺序排好的链表,返回其头指针
}
structnode*hebing(structnode*h)//定义合并函数,并返回合并后的链表的头指针
{
structnode*p,*q,*r;//定义三个结构体标记指针
p=h;
q=p->next;
while(q!
=NULL)
{
if(p->expo==q->expo)
{
p->coef=p->coef+q->coef;
r=q->next;
free(q);
p->next=r;
if(r!
=NULL)
{
q=r->next;
p=r;
}
}
else
{
p=p->next;
q=q->next;
}
}
returnh;
}
voidprint(structnode*h)//定义输出链表函数
{
structnode*p;//定义标记指针,输出链表
p=h;
while(p!
=NULL)
{
if(p->coef==0)p=p->next;//系数为零时跳过
else
{
if(p->coef<0)//系数为负时应加上括号
{
if(p->expo==0)printf("(%.2f)+",p->coef);
elseprintf("(%.2f)*X^%d+",p->coef,p->expo);
}
else
{
if(p->expo==0)printf("%.2f+",p->coef);
elseprintf("%.2f*X^%d+",p->coef,p->expo);
}
p=p->next;
}
}
printf("\b\b\n");
}
structnode*add(structnode*h1,structnode*h2)//定义加法函数,并返回结果的链表的头指针
{
structnode*p,*q,*head,*r;//定义结构体头指针head和标记指针p,q,r
p=h1;
q=h2;
head=(structnode*)malloc(sizeof(link));
if(p->expo>=q->expo){head=h1;p=p->next;}
else
{
if(p->expoexpo){head=h2;q=q->next;}
else{p->coef=p->coef+q->coef;head=p;p=p->next;q=q->next;}
}
r=head;
while(p!
=NULL&&q!
=NULL)
{
if(p->expo>q->expo){r->next=p;p=p->next;}
else
{
if(p->expoexpo){r->next=q;q=q->next;}
else{p->coef=p->coef+q->coef;r->next=p;p=p->next;q=q->next;}
}
r=r->next;
}
if(p==NULL&&q==NULL)r->next=NULL;
else
{
if(p==NULL)r->next=q;
if(q==NULL)r->next=p;
}
returnhead;
}
main()
{
structnode*h1,*h2,*h3;//定义三个结构体头指针标记多项式
h1=create();
h1=order(h1);
h1=hebing(h1);
print(h1);
h2=create();
h2=order(h2);
h2=hebing(h2);
print(h2);
h3=add(h1,h2);
h3=hebing(h3);
print(h3);
}
(2)顺序存储结构
此方法中也定义一个结构体类型:
structpoly
{
floatcoef;
intexpo;
}dxs[15],dxs1[15],dxs2[30];
voidcreate(intn)//定义建立结构体数组函数
{
inti;//定义数组中的循环标记数据i
for(i=0;i{
scanf("%f",&dxs[i].coef);
scanf("%d",&dxs[i].expo);
}
}
voidprint(intn)//定义结构体数组输出函数
{
inti;//定义数组中的循环标记数据i
for(i=0;i{
if(dxs[i].coef<0)
{
if(dxs[i].expo==0)printf("(%.2f)+",dxs[i].coef);
elseprintf("(%.2f)*X^%d+",dxs[i].coef,dxs[i].expo);
}
elseif(dxs[i].coef>0)
{
if(dxs[i].expo==0)printf("%.2f+",dxs[i].coef);
elseprintf("%.2f*X^%d+",dxs[i].coef,dxs[i].expo);
}
}
printf("\b\b\n");
}
voidorder(intn)//定义排序函数
{
inti,temp1,j;//定义数组中的循环标记数据i与j,和整型标记temp1
floattemp2;//定义单精度型标记temp2
for(i=0;ifor(j=i+1;j{
if(dxs[j].expo>dxs[i].expo)
{
temp1=dxs[j].expo;
dxs[j].expo=dxs[i].expo;
dxs[i].expo=temp1;
temp2=dxs[j].coef;
dxs[j].coef=dxs[i].coef;
dxs[i].coef=temp2;
}
}
for(i=0;i{
if(dxs[i].expo==dxs[i+1].expo)
{
dxs[i+1].coef=dxs[i].coef+dxs[i+1].coef;
if(i==n-2)
{
dxs[i].coef=dxs[i+1].coef;
dxs[i+1].coef=0;
}
else
{
for(j=i;j{
dxs[j].coef=dxs[j+1].coef;
dxs[j].expo=dxs[j+1].expo;
}
dxs[j].coef=0;
i--;
}
}
}
}
voidadd(intn1,intn2)//定义加法函数
{
inti=0,j=0,p,m;//定义数组中的循环标记数据i,j,p,m
for(p=0;;p++)
{
if(dxs[i].expo==dxs1[j].expo)
{
dxs2[p].coef=dxs[i].coef+dxs1[j].coef;
dxs2[p].expo=dxs[i].expo;
i++;
j++;
}
else
{
if(dxs[i].expo>dxs1[j].expo)
{
dxs2[p].coef=dxs[i].coef;
dxs2[p].expo=dxs[i].expo;
i++;
}
else
{
dxs2[p].coef=dxs1[j].coef;
dxs2[p].expo=dxs1[j].expo;
j++;
}
}
if(i==n1||j==n2)
{
p++;
break;
}
}
if(i==n1)
for(;j{
dxs2[p].coef=dxs1[j].coef;
dxs2[p].expo=dxs1[j].expo;
p++;
}
else
for(;i{
dxs2[p].coef=dxs[i].coef;
dxs2[p].expo=dxs[i].expo;
p++;
}
for(m=0;m
{
if(dxs2[m].coef<0)
{
if(dxs2[m].expo==0)printf("(%.2f)+",dxs2[m].coef);
elseprintf("(%.2f)*X^%d+",dxs2[m].coef,dxs2[m].expo);
}
elseif(dxs2[m].coef>0)
{
if(dxs2[m].expo==0)printf("%.2f+",dxs2[m].coef);
elseprintf("%.2f*X^%d+",dxs2[m].coef,dxs2[m].expo);
}
}
printf("\b\b\n");
}
main()
{
intn1,n2,i;//定义多项式的项数n1与n2,和循环标记数据i
scanf("%d",&n1);
create(n1);
order(n1);
print(n1);
for(i=0;idxs1[i].coef=dxs[i].coef;
dxs1[i].expo=dxs[i].expo;
}
scanf("%d",&n2);
create(n2);
order(n2);
print(n2);
add(n1,n2);
}
4.调试分析
(1)链接存储结构
在此方法的实现过程中,没有比较大的麻烦,因为最近一直在用链表进行编程,已经比较熟悉了链表的基本操作,只是在一些实现方便与否、接近真实情况与否进行了一番思考。
首先,我因为做题的习惯,所以没有考虑到假如输入多项式时可以打乱顺序输入,即不按照降幂或升幂的形式进行输入。
意识到可能有此情况后,我就添加了一个order函数,对输入的原多项式进行排序,解决掉因打乱顺序输入而导致程序出错的可能性。
之后,又有人提出,假如多项式中有指数相同的项,那如果没有合并一类作用的函数做整理的话,也会出错。
因此,我又着手编一个合并函数。
合并函数其实不难,只要把原多项式进行排序后就变得很简单了。
只需要将指数相同的项的系数进行加法运算,之后删去后一个节点即可。
最后,还有一个输出形式的问题。
因为假如系数是负数的时候,需要将其用括号括起来,这也是数学运算中的规定。
因此,我又对输出函数:
print函数进行了一些修改,并且在修改过程中又发现,假如指数为零时,输出的应该是只有系数,所以我又顺便将这方面的漏洞加以补充。
当然,我这个程序毕竟还是有不足之处的。
一、没有利用到链表的一项基本操作:
删除节点。
在输出过程中,我对系数为零的节点的处理方式是跳过,而不是删除,虽然不会影响到最终的输出结果,但对内存其实是有一些浪费,毕竟程序需要的不仅是结果正确,而且还要做到时间和空间上的节约。
二、当一项的指数为1时,应当输出的是X,而不是X^1,所以此方面仍需要改进。
虽然此项改进不是很难,但由于时间紧迫,没有来得及修改,但我会在以后的空闲时间内将其完善。
在算法的时空复杂度上,我没有进行过多的考虑,因为现在自己的水平还没有那么高,我只知道,在排序函数中,我用的冒泡排序方法是一种效率很低的方法,时间复杂度为O(n2)。
而同学向我推荐过的一种插入排序方法,一种部分有序的排序方法,算下来时间复杂度为O(n2-n),因此自己还需要将此程序加以改进。
(2)顺序存储结构
在此方法的实现过程中,我确实费了很大的时间。
因为数组很长时间没有用到过了,很多基本操作又比链表复杂,因此,我花了相当长的时间才将此程序完成。
定义结构体数组方面虽然很简单,但用起来就会变的相当复杂,并且由于自己的数组方面的知识不是很牢靠,因此,语法错误很多,调试费了很长的时间,并且很多次无法通过编译。
最终在同学的帮助下,自己又花了大量的时间,终于将程序编出。
因为程序需要的作用函数已在链表方法中掌握,所以此项内容里我没有进行更多的考虑,只是感觉用结构体数组实现的时候,将排序函数和合并函数写在一起会更加方便,所以此方法中我只设置了一个排序函数,并且在做加法的函数中附带了输出作用,因此不再调用print函数输出数组。
但此相加的函数似乎有点问题,在多项式比较复杂的时候,输出总是有点问题。
自己研究了很长时间之后还是找不出问题,希望老师能发现并指出,完善此程序。
通过编此程序,我感觉到自己在数组的知识点上掌握的不够扎实,以后还需多加练习,熟练掌握数组的基本操作方法。
5.用户使用说明
(1)链接存储结构
运行程序后,会出现提示:
请输入第一个多项式
请输入多项式的项数:
(这时应输入其项数(整型数据),后按回车键;比如输入:
2)
请输入第1项的系数:
请输入第1项的指数:
(比如依次输入2,2)
请输入第2项的系数:
请输入第2项的指数:
(比如依次输入3,3)
输入的第一个多项式为:
2.00*X^2+3.00*X^3
按降幂排列后多项式为:
3.00*X^3+2.00*X^2
请输入第二个多项式;
请输入多项式的项数:
(比如输入:
2)
请输入第1项的系数:
请输入第1项的指数:
(比如依次输入1,1)
请输入第2项的系数:
请输入第2项的指数:
(比如依次输入2,2)
输入的第一个多项式为:
1.00*X^1+2.00*X^2
按降幂排列后多项式为:
2.00*X^2+1.00*X^1
相加后的多项式为:
3.00*X^3+4.00*X^2+1.00*X^1
(2)顺序存储结构
请输入第一个多项式的项数:
(比如输入:
2)
请输入第1项的系数:
请输入第1项的指数:
(比如依次输入2,2)
请输入第2项的系数:
请输入第2项的指数:
(比如依次输入3,3)
您输入的第一个多项式为:
2.00*X^2+3.00*X^3
降幂排序后该多项式变为:
3.00*X^3+2.00*X^2
请输入第二个多项式的项数:
(比如输入:
2)
请输入第1项的系数:
请输入第1项的指数:
(比如依次输入1,1)
请输入第2项的系数:
请输入第2项的指数:
(比如依次输入2,2)
您输入的第一个多项式为:
1.00*X^1+2.00*X^2
降幂排序后该多项式变为:
2.00*X^2+1.00*X^1
两个多项式相加后的结果为:
3.00*X^3+4.00*X^2+1.00*X^1
6.测试结果
(1)链接存储结构
(2)顺序存储结构
7.附录
(1)链接存储结构
#include"stdio.h"
#include"stdlib.h"
structnode
{
floatcoef;//定义系数为float类型数据
intexpo;//定义指数为int类型数据
structnode*next;
}link;
structnode*create()//定义建立多项式函数,并返回链表头指针
{
structnode*h=NULL,*q,*p;//定义结构体头指针h,标记指针p和q
inti=1,N;//定义多项式的项数N及标记数i
printf("请输入多项式的项数:
");
scanf("%d",&N);
for(;i<=N;i++)
{p=(structnode*)malloc(sizeof(link));//为下一个节点分配空间
printf("请输入第%d项的系数:
",i);
scanf("%f",&p->coef);
fflush(stdin);
printf("请输入第%d项的指数:
",i);
scanf("%d",&p->expo);
fflush(stdin);
if(i==1){h=p;q=p;}//建立头节点
else
{
q->next=p;
q=p;
}
}
q->next=NULL;
p->next=NULL;
returnh;
}
structnode*order(structnode*h)//定义排序函数,并返回整理后的链表的头指针
{
structnode*p,*q,*t,*h1,*h2;//定义三个结构体标记指针和两个头指针
h1=h;//建立一个新的链表,头指针为h,指向原链表的第一个节点,之后将原链表中的节点一个一个的插入此链表,进行排序
h2=h1->next;//将原来的链表建立成待排序链表
h1->next=NULL;//截断第一个原链表中的节点
while(h2!
=NULL)
{
q=h1;
p=q->next;
t=h2;//从待排序链表中选出一个节点准备插入到新链表中
h2=h2->next;//移动待排序链表的头指针,便于进行下一次挑选
t->next=NULL;
if(t->expo>q->expo)//应插入头指针之前的情况
{
t->next=q;
h1=t;
continue;
}
if(p==NULL&&t->expo<=q->expo)q->next=t;//应插入表尾的情况