班级 : ****
学号 : 201907020633
姓名 : ***
实验机号: A3
实验日期 :2020.12.04
报告日期 :2020.12.07
此次实验实现的功能有:
1.多项式加法
2.多项式减法(poly1-poly 2)
3.多项式乘法
4.多项式求值
5.多项式求导
6.多项式求不定积分
亮点:
对于运行中产生的数据文件如生成的多项式,运行结果,操作次数以及运行时间的存储,存储方式为仿系统日志文件的模式进行记录。方便对生成数据的分析以及对于错误数据的筛查和追溯。每次运行结果都会产生时间戳,保证数据的可靠性。
存储方案: 链式存储(方便插入和删除,顺序存储的插入和删除需要移动大量的数据,造成许多不必要的时间消耗)
实验逻辑:
在poly 1.txt和poly 2.txt文件中生成随机数。
当程序开始运行时数据被读入程序,同时被写入log.txt中作以记录。
继而进行下一步操作,如加减法、乘法、求值、求导、求不定积分。
执行完运算操作之后,将运算结果同时输出至屏幕和log.txt文件中。
如果需要继续执行,则将poly 1.txt和ploy 2.txt文件中的数据擦除,并重复上述操作。
- 创建多项式文件
思想:运用文件操作,生成随机数存储入poly 1.txt和poly 2.txt中。
控制生成项数在指定范围内(即,rand()%11),尽量保持运算结果和生成数据方便分析,避免因为数据过大,无法及时发现计算中出现的错误。
void creat()
{
char s1[20]="poly 1.txt", s2[20]="poly 2.txt";
srand((int)time(0));
int n1 = rand()%10+1;
FILE *fp1=fopen(s1,"w");
for (int i=1;i<=n1;i++)
{ if (i==1)
fprintf(fp1,"%d", rand()%11);
else fprintf(fp1," %d", rand()%11);
}
fclose (fp1);
int n2=rand()%10+1;
FILE *fp2=fopen(s2,"w");
for (int i=1;i<=n2;i++)
{ if (i==1)
fprintf(fp2,"%d", rand()%11);
else fprintf(fp2," %d", rand()%11);
}
fclose (fp2);
}
- 从文件中读入数据,生成多项式
思想:运用feof,当文件中数据未被完全读入程序中时,保持运行。
且如果指数相同时,系数相加。
PolyPtr getPoly (char *filename)
{
PolyPtr poly=NULL,p;
FILE *fp=fopen (filename,"r");
if (!fp) return poly;
poly= (PolyPtr)malloc(sizeof(Poly)) ;
poly->coef=0;
poly->expn=0;
poly->next=NULL;
while (!feof(fp))
{
p= (PolyPtr)malloc(sizeof(Poly)) ;
p->coef=0;
p->expn=0;
fscanf(fp,"%f %d",&p->coef,&p->expn);
if (p->coef==0)
{
free(p);
continue;
}
PolyPtr pre=poly;
PolyPtr q=poly->next;
while (q&&q->expn<p->expn)
{
pre=q;
q=q->next;
}
if (q&&q->expn==p->expn)
{
q->coef+=p->coef;
free(p);
continue;
}
p->next=q;
pre->next=p;
}
return poly;
}
- 将运算结果和生成的多项式输出到屏幕上。
思想:通过遍历输出多项式。
void PrintPoly(PolyPtr poly)
{
PolyPtr p = poly->next;
if (!poly)
return;
while (p && p->coef == 0)
p = p->next;
FILE* file = fopen("log.txt", "a");
if (!p)
{
printf("0");
fprintf(file, "0\n");
return;
}
if (p->expn != 0)
{
printf("%.2f x^%d", p->coef, p->expn);
fprintf(file, "%.2f x^%d", p->coef, p->expn);
}
else {
printf("%.2f", p->coef);
fprintf(file, "%.2f", p->coef);
}
p = p->next;
while (p)
{
if (p->coef != 0)
{
if (p->expn != 0)
{
if (p->coef > 0)
{
printf("+ %.2f x^%d", p->coef, p->expn);
fprintf(file, "+ %.2f x^%d", p->coef, p->expn);
}
else {
printf(" %.2f x^%d", p->coef, p->expn);
fprintf(file, "% .2f x ^ %d", p->coef, p->expn);
}
}
else
{
if (p->coef > 0)
{
printf("+ %.2f", p->coef);
fprintf(file, "+ %.2f", p->coef);
}
else {
printf(" %.2f", p->coef);
fprintf(file, " %.2f", p->coef);
}
}
}
p = p->next;
}
fclose(file);
}
- 多项式加法
思想:
(1)对于p1和p2初始化,然后指向Pa,Pb的首元;
(2)p3指向Pc的当前结点,初值为Pa的头结点;
(3)当指针p1和p2均未到达相应表尾时,则循环比较p1和p2所指结点对应的指数值:
if:p1->expn == p2->expn
,两个结点中系数相加,若不为零,则修改p1所指结点值,同时删除p2所指结点,若和为零,则删除p1和p2所指结点;
elif:p1->expn < p2->expn
,则应该摘取p1所指结点插入到和多项式链表中去;else:p1->expn >p2->expn,
则应该摘取p2所指结点插入到和多项式链表中去;
(4) 将非空多项式的剩余段插入到p3所指结点之后;
(5)释放Pb的头结点;
减法类似,将每项的系数置反,后续操作和加法相同。
PolyPtr Add(PolyPtr pa, PolyPtr pb)
{
PolyPtr p1=pa->next,p2=pb->next;
PolyPtr p3=pa;
PolyPtr r;
while (p1&&p2)
{
if (p1->expn==p2->expn)
{ cent++;
float sum=p1->coef+p2->coef;
if (sum!=0)
{
p1->coef=sum;
p3->next=p1;
p3=p1;
r=p2;
p2=p2->next;
free(r);
p1=p1->next;
}
else {
r=p2;
p2=p2->next;
free(r);
r=p1;
p1=p1->next;
free(r);
}
}
else if(p1->expn<p2->expn)
{
p3->next=p1;
p3=p1;
p1=p1->next;
}
else if(p1->expn>p2->expn)
{
p3->next=p2;
p3=p2;
p2=p2->next;
}
cent++;
}
p3->next=p1?p1:p2;
cent++;
free (pb);
return pa;
}
- 多项式乘法
思想:借助辅助空链表L,利用poly1的指针所指的节点数值乘poly2每一项,将结果存储在链表L中。然后将指向该节点的指针后移到下一个节点重复上述操作;
PolyPtr Mult(PolyPtr pa, PolyPtr pb)
{
PolyPtr p1=pa->next, p2=pb->next;
PolyPtr p3=(PolyPtr) malloc(sizeof(Poly));
p3->next=0;
PolyPtr head=p3;
while (p1&&p2)
{
cent++;
PolyPtr pnew=(PolyPtr) malloc(sizeof(Poly));
pnew->next=0;
pnew->coef=p1->coef*p2->coef;
pnew->expn=p1->expn+p2->expn;
p3->next=pnew;
p3=p3->next;
p2=p2->next;
}
p1=p1->next;
while (p1)
{
PolyPtr p4=(PolyPtr) malloc(sizeof(Poly));
p4->next=0;
PolyPtr p5=p4;
p2=pb->next;
while (p2)
{ cent++;
PolyPtr pnew1=(PolyPtr) malloc(sizeof(Poly));
pnew1->next=0;
pnew1->coef=p1->coef*p2->coef;
pnew1->expn=p1->expn+p2->expn;
p4->next=pnew1;
p4=p4->next;
p2=p2->next;
}
Add(head,p5);
p1=p1->next;
}
return head ;
}
- 多项式求值
思想:遍历后逐项取值,后对所有值相加
float GetValue (PolyPtr p)
{ float x;
printf ("设x的值为:");
scanf ("%f",&x);
FILE* fp0 = fopen("log.txt", "a");
fprintf(fp0, "\nget valuex=%.2f\n", x);
PolyPtr p1=p->next;
float sum=0;
while (p1)
{ cent++;
sum+=p1->coef*pow(x,p1->expn);
p1=p1->next;
}
printf ("多项式求值得到:%.2f\n",sum);
fprintf(fp0,"sum = %.2f",sum);
fclose(fp0);
return sum;
}
- 多项式求导
思想:通过遍历的方式,按照数学的规则进行运算。指数为零时,系数归零。其他的情况下,指数-1,对于系数*原指数。
PolyPtr GetDerivation (PolyPtr p)
{
PolyPtr head=p;
PolyPtr p1=p->next;
while (p1)
{ cent++;
if (p1->expn==0)
p1->coef=0;
else
{
p1->coef=p1->coef*p1->expn;
p1->expn-=1;
}
p1=p1->next;
}
return head;
}
- 多项式求不定积分
思想:通过遍历每一项,并对每项进行该操作后,指数+1,系数除以指数,按照正常的数学规则进行。
PolyPtr Getlntegration(PolyPtr p)
{ PolyPtr head=p;
PolyPtr p1=p->next;
while (p1)
{ cent++;
if (p1->expn==0)
p1->expn+=1;
else{
p1->coef=p1->coef/(1+p1->expn);
p1->expn+=1;
}
p1=p1->next;
}
return head;
}
- 销毁
思想:通过遍历逐项释放空间
void Destroy (PolyPtr poly)
{ PolyPtr p=poly->next;
while (poly)
{
p=poly->next;
free(poly);
poly=p;
}
}
测试数据:
1.00 x^1+ 3.00 x^6
Add result:1.00 x^1+ 3.00 x^6
|--->>> 2.59sec 1times 2020-12-6 23:21:48
9.00 x^4+ 3.00 x^6
18.00 x^1+ 5.00 x^9+ 7.00 x^10
Minus result:-18.00 x^1+ 9.00 x^4+ 3.00 x^6-5.00 x ^ 9-7.00 x ^ 10
|--->>> 6.29sec 7times 2020-12-6 23:21:51
7.00 x^6+ 4.00 x^7+ 2.00 x^8
8.00+ 5.00 x^1
Mult result:56.00 x^6+ 67.00 x^7+ 36.00 x^8+ 10.00 x^9
|--->>> 10.23sec 15times 2020-12-6 23:21:55
9.00 x^8+ 12.00 x^9+ 1.00 x^10
7.00+ 1.00 x^1+ 10.00 x^3+ 9.00 x^5
Minus result:-7.00-1.00 x ^ 1-10.00 x ^ 3-9.00 x ^ 5+ 9.00 x^8+ 12.00 x^9+ 1.00 x^10
|--->>> 12.41sec 9times 2020-12-6 23:21:57
5.00 x^4+ 2.00 x^10
11.00+ 2.00 x^1
Getvalue poly 1,poly 2 :
get valuex=1.00
sum = 7.00
get valuex=2.00
sum = 15.00
|--->>> 16.62sec 4times 2020-12-6 23:22: 2
3.00 x^6
6.00 x^1+ 5.00 x^3+ 4.00 x^4+ 9.00 x^6
GetDerivation result poly 1,poly 2:
18.00 x^5
6.00+ 15.00 x^2+ 16.00 x^3+ 54.00 x^5
|--->>> 19.54sec 5times 2020-12-6 23:22: 4
5.00 x^1+ 13.00 x^5+ 8.00 x^7+ 10.00 x^10
7.00+ 5.00 x^9
Minus result:-7.00+ 5.00 x^1+ 13.00 x^5+ 8.00 x^7-5.00 x ^ 9+ 10.00 x^10
|--->>> 24.39sec 8times 2020-12-6 23:22: 9
2.00+ 8.00 x^2+ 5.00 x^3
Add result:2.00+ 8.00 x^2+ 5.00 x^3
|--->>> 25.93sec 1times 2020-12-6 23:22:11
7.00 x^1+ 4.00 x^4+ 3.00 x^5+ 3.00 x^9+ 2.00 x^10
8.00+ 7.00 x^3+ 1.00 x^4+ 14.00 x^6
Mult result:56.00 x^1+ 81.00 x^4+ 31.00 x^5+ 126.00 x^7+ 25.00 x^8+ 27.00 x^9+ 72.00 x^10+ 42.00 x^11+ 21.00 x^12+ 17.00 x^13+ 2.00 x^14+ 42.00 x^15+ 28.00 x^16
|--->>> 28.02sec 62times 2020-12-6 23:22:13
8.00+ 7.00 x^9+ 7.00 x^10
1.00 x^1+ 7.00 x^2
Minus result:8.00-1.00 x ^ 1-7.00 x ^ 2+ 7.00 x^9+ 7.00 x^10
|--->>> 29.80sec 6times 2020-12-6 23:22:15
5.00+ 5.00 x^1+ 3.00 x^2+ 2.00 x^7+ 7.00 x^10
9.00+ 8.00 x^6+ 1.00 x^9+ 2.00 x^10
GetDerivation result poly 1,poly 2:
5.00+ 6.00 x^1+ 14.00 x^6+ 70.00 x^9
48.00 x^5+ 9.00 x^8+ 20.00 x^9
|--->>> 35.23sec 9times 2020-12-6 23:22:20
9.00 x^5
8.00+ 11.00 x^2+ 6.00 x^7+ 5.00 x^9
Getvalue poly 1,poly 2 :
get valuex=1.00
sum = 9.00
get valuex=2.00
sum = 3380.00
|--->>> 41.87sec 5times 2020-12-6 23:22:27
8.00 x^3
1.00 x^3+ 2.00 x^5+ 9.00 x^6
Getvalue poly 1,poly 2 :
get valuex=1.00
sum = 8.00
get valuex=2.00
sum = 648.00
|--->>> 54.27sec 4times 2020-12-6 23:22:39
10.00 x^2+ 10.00 x^8
7.00+ 3.00 x^1+ 10.00 x^7
GetDerivation result poly 1,poly 2:
20.00 x^1+ 80.00 x^7
3.00+ 70.00 x^6
|--->>> 62.43sec 5times 2020-12-6 23:22:47
9.00+ 4.00 x^2+ 3.00 x^6
3.00 x^5+ 6.00 x^10
Add result:9.00+ 4.00 x^2+ 3.00 x^5+ 3.00 x^6+ 6.00 x^10
|--->>> 64.50sec 5times 2020-12-6 23:22:49
9.00 x^1+ 12.00 x^5
2.00
Minus result:-2.00+ 9.00 x^1+ 12.00 x^5
|--->>> 68.19sec 3times 2020-12-6 23:22:53
写出代码调试过程中遇到的问题及解决办法
主要遇到的问题: 文件指针加载项目相重叠,导致文件读写错误,文件多次重复打开;遇到未加载项。
解决方案: 及时关闭文件,并对每个文件指针逐个命名,防止文件指针重复命名。
经过多次的修改,所的实验结果基本符合预期结果。
对于运行时间的计算相对于实际消耗时间有一定偏差。
原代码
printf(“运行时间:%.2lf秒\n”, (double)clock() / CLOCKS_PER_SEC);
改进解决方案:
clock_t start, finish;
double duration;
start = clock();
//操作
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf(“运行时间:%.2lf秒\n”,duration);
不同的运算操作产生的时间消耗不同,不同的数据规模所产生的时间消耗也有所不同。当问题规模较小时,乘法所花费的时间相对较少;当问题规模较大时,加减法所消耗的时间较少,数据量越大差异越明显。
对实验的测量结果进行图示化呈现,分析算法性能,并给出优化方法
问题规模 | 10 | 100 | 1000 | 10000 | 0 |
---|---|---|---|---|---|
加法 | 2.11 | 2.16 | 2.15 | 10.36 | 运行时间 |
乘法 | 1.93 | 1.68 | 6.11 | 35.42 | 0 |
优化方法:将乘法转换为加法,通过增加空间的方法换取时间性能上的提升。
通过本次实验加深了对于线性表的各项操作使用的印象,如线性表的遍历,线性表的插入删除,以及线性表的合并。
在仿日志的操作中也学会了生成时间戳的操作,如调用windows和time库。除此之外,对于文件各项操作也有了较为深入的了解。对于log.txt文件的探究过程中也对文件的读写存储过程有了较为深入的了解。
对于数据的分析过程中,由于对于excel表格相关的操作不太熟悉,导致制作的图表有很多的瑕疵,在以后的数据分析当中我会加强这方面的学习,毕竟excel等办公软件对于数据简单处理的过程,以及数据图示化有着极其重要的用途。
通过实验的调试,以及同学的帮助,这次实验中遇到的许多问题都得到了很好的解决。因此深深地体会到了知识是在探究中产生的,得到解决的。因此遇到问题不能只一个人在那冥思苦想,只有众人拾柴火焰高,才能获得更大的收获。