问题描述:
利用链表实现一元多项式的数学运算。如一元多项式
可以利用其系数𝑝和指数𝑒组合的方式实现链式存储。通过对线性表的基本操作,例如插入,删除,查找等可以实现一元多项式的复杂运算,比如加,减,乘,除等运算。
基本要求:
利用链表存储一元多项式,通过对链表的操作实现多项式的运算。
测试数据:
对于多项式:𝐴(𝑥) = 7 + 3𝑥 + 9𝑥 + 5𝑥,𝐵(𝑥) = 8𝑥 + 22𝑥 − 9𝑥,实现加,减,乘和微分,输出结果。
解答:
实现思路:
代码结构为主分形式,主函数主要为一些提示,具体的输入输出则将参数传递到分函数中实现。分函数有创建一元多项式、多项式升幂排序、比较项指数大小、打印多项式、加法运算、减法运算、微分运算和乘法运算等。比较需要关注的是乘法方面的实现,思路是将乘法运算分解为一系列的加法运算。不过在这里着实纠结了好多天,本来呢觉得实现乘法自己应该为它再另外构造一个加法算法提供接口,以便实现它的加法迭代。可是呢,这样完全行不通,打印出来的都是0.0,自己完全不晓得为什么,重复对着代码思考了好多次了,觉得没什么毛病,但就是行不通——
然后呢,大概是前天吧!自己捣弄了半天代码调试依旧不会的情况下,决定回归输出调试,于是就在乘法函数里注释掉了迭代用的加法,另外在加法循环体外面上头加了两句打印语句想看看多项式A和多项式B的每一项相乘后得到的结果是咋样的。
于是乎奇迹就诞生了,用x^1+2x^2+3x^3和x^1作为测试数据,莫名其妙地乘法结果就给打印出来了,完全没有用到我费了九牛二虎之力写出来的迭代加法——
不过显示结果还是有点小bug,显示出来的是正确结果的相反数,而且主函数返回值也不是正常的0,而是莫名其妙的3221225477
接着本着修bug的精神就在乘法函数里运算部分乘了个负一,这下结果就好看了,如下(返回值依旧不正常)
但是,天下怎么会有凭空掉馅饼这等好事!?自己再用上面给出的复杂测试数据跑了下,这下就没那么好看了,得出来的是一个明显错误的结果(。﹏。*)
而且也发现了微分算法部分的一个小bug——
好吧,只能后续继续改进了,自己应该是在指针理解上出现了问题,回头去《深入理解C指针》。
另外,假如用户输入的两个一元多项式为相同的话,输出也会有点不正常,需要弄弄。看来有点眉目了
11.25这天晚上,我终于弄明白了bug的缘由——丫蛋自己没把Pd给初始化!,而且打印函数如果给它的参数是个空地址的话,它会在那儿瞎转悠几圈,然后返回个不是0的返回值,直接结束程序——(还修复了打印首项有时会出现加号的小bug)
还存在一个问题,就是如果输入的两个多项式是相同的话,减法那部分结果会不显示任何值,而不是0。得弄弄
(已解决)
OK,下面就贴下自己的代码了,折腾带注释版本,以及去掉无关注释~纯净版本^_^
实现代码(折腾注释版):
#include<stdio.h>
#include<stdlib.h>
typedef struct term{
float coef;
int expn;
struct term *next;
}term,*LinkList;
typedef LinkList polynomial;
int cmp(LinkList pa,LinkList pb) //比较各项指数大小
{
if(pa->expn > pb->expn)
return 1;
else if(pa->expn == pb->expn)
return 0;
else
return -1;
}
int LocateElem(LinkList L,LinkList t,LinkList *q) /*定位项数指数大小,使多项式按升幂排序 这里的*q起到内存保护的作用*/
{
LinkList p1=L->next;
LinkList p2=L;
while(p1)
{
if(t->expn > p1->expn)
{
p1=p1->next;
p2=p2->next;
}
else if(t->expn == p1->expn)
{
*q=p1;
return 1;
}
else
{
*q=p2;
return 0;
}
}
*q=p2;
return 0;
}
void CreatePolyn(polynomial P) //建立多项式所需的各项具体值
{
LinkList t;
LinkList q;
P->coef=0.0;
P->expn=-1;
P->next=NULL;
printf("Please input coefficient and exponent below in format like 1,2 and end with 0,0:\n");
t=(LinkList)malloc(sizeof(term));
// if(!t) exit(OVERFLOW); //借鉴教材《数据结构(C语言版)》的代码风格...没用
t->next=NULL;
scanf("%f,%d",&t->coef,&t->expn);
while(t->coef||t->expn) //约定0,0结束输入,实现动态输入多项式
{
if(!LocateElem(P,t,&q)) /*每次输入的指数都应不同,转移指针P->q,而且实现指数排序(这里 &q 博大精深, 利用指针的指针之妙法确保指针不被篡改,在LocateElem内部又机智地取回———)*/
{
t->next=q->next; /*1.q->next = NULL,2.q->next = t, 也改变了P->next的值 P与q共享内存*/
q->next=t; //对t, 头插法, 对q, 尾插法
}
t=(LinkList)malloc(sizeof(term));
// if(!t) exit(OVERFLOW);
t->next=NULL;
scanf("%f,%d",&t->coef,&t->expn);
}
}
void printPolyn(polynomial P) //打印多项式
{
LinkList q;
q=P->next;
if(!q)
{
printf("0\n"); //针对两多项式相同的情况
}
while(q)
{
if(q->coef==0) /*主要针对微分的常数项情况,可是出现了下一项变为首项但其前面加号没有去掉的情况。。。*/
{
printf("");
q=q->next; /*将此if结构与下面if结构分开,不耦合,解决打印首项带加号问题*/
}
if(q->expn==0) //判断指数是否为零及正负,调整输出格式
{
printf("%.2f",q->coef);
q=q->next;
}
else if(q->expn>0)
{
printf("%.2f*x^%d",q->coef,q->expn);
q=q->next;
}
else
{
printf("%.2f*x^(%d)",q->coef,q->expn);
q=q->next;
}
if(q) //判断下一项系数正负,调整输出格式
{
if(q->coef>0)
printf("+");
else
printf("");
}
else
printf("\n");
}
}
void AddPolyn(polynomial Pa,polynomial Pb,polynomial Pc) /*不完全参照教科书上的思路,而是另外开辟空间存储和,不释放原来数据空间*/
{
LinkList qa=Pa->next;
LinkList qb=Pb->next;
LinkList qc=Pc;
LinkList head=qc;
LinkList s;
float sum;
Pc->coef=0.0;
Pc->expn=-1;
Pc->next=NULL;
while(qa&&qb)
{
switch(cmp(qa,qb))
{
case -1:
s=(LinkList)malloc(sizeof(term));
//if(!s) exit(OVERFLOW);
*s=*qa;
qc->next=s;
qc=s;
qa=qa->next;
break;
case 0:
sum=qa->coef+qb->coef;
if(sum!=0.0)
{
s=(LinkList)malloc(sizeof(term));
//if(!s) exit(OVERFLOW);
*s=*qa;
s->coef=sum;
qc->next=s;
qc=s;
qa=qa->next;
qb=qb->next;
}
else
{
qc->next=qa->next;
qa=qa->next;
qb=qb->next;
}
break;
case 1:
s=(LinkList)malloc(sizeof(term));
// if(!s) exit(OVERFLOW);
*s=*qb;
qc->next=s;
qc=s;
qb=qb->next;
break;
}
}
qc->next=qa?qa:qb; //添加NULL尾巴
Pc=head;
}
void SubPolyn(polynomial Pa,polynomial Pb,polynomial Pc) /*思路同前面加法,减法变加法,前面加负号, 另外开辟空间存储差*/
{
LinkList qa=Pa->next;
LinkList qb=Pb->next;
LinkList qc=Pc;
LinkList head=qc;
LinkList s;
float differ;
Pc->coef=0.0;
Pc->expn=-1;
Pc->next=NULL;
while(qb) //为减数加负号
{
qb->coef=0-(qb->coef);
qb=qb->next;
}
qb=Pb->next;
while(qa&&qb)
{
switch(cmp(qa,qb))
{
case -1:
s=(LinkList)malloc(sizeof(term));
// if(!s) exit(OVERFLOW);
*s=*qa;
qc->next=s;
qc=s;
qa=qa->next;
break;
case 0:
differ=qa->coef+qb->coef;
if(differ!=0.0)
{
s=(LinkList)malloc(sizeof(term));
// if(!s) exit(OVERFLOW);
*s=*qa;
s->coef=differ;
qc->next=s;
qc=s;
qa=qa->next;
qb=qb->next;
}
else
{
qc->next=qa->next;
qa=qa->next;
qb=qb->next;
}
break;
case 1:
s=(LinkList)malloc(sizeof(term));
// if(!s) exit(OVERFLOW);
*s=*qb;
qc->next=s;
qc=s;
qb=qb->next;
break;
}
}
qc->next=qa?qa:qb;
Pc=head;
}
void AddPolyn_multi(polynomial Pa,polynomial Pb) /*构造一个可以用于乘法项数迭代的特殊加法,释放空间,和储存至Pa,方便迭代累加*/
{
LinkList qa=Pa->next; //这两句导致项数错位了?
LinkList qb=Pb->next;
//LinkList qa=Pa;
//LinkList qb=Pb;
LinkList qc=Pa;
LinkList head=qc;
LinkList s,s1,s2;
float sum;
while(qa&&qb)
{
switch(cmp(qa,qb))
{
case -1:
qc->next=qa;
qc=qa;
qa=qa->next;
break;
case 0:
sum=qa->coef+qb->coef;
if(sum!=0.0)
{
s=qb;
qa->coef=sum;
qc->next=qa;
qc=qa;
qa=qa->next;
qb=qb->next;
free(s);
}
else
{
s1=qa;
s2=qb;
qc->next=qa->next;
qa=qa->next;
qb=qb->next;
free(s1);
free(s2);
}
break;
case 1:
qc->next=qb;
qc=qb;
qb=qb->next;
break;
}
}
qc->next=qa?qa:qb;
Pa=head; //千思万虑老子终于把你给揪出来了,原来是形参搞得鬼!?
//printPolyn(Pa);
//pirntf("\n");
// free(Pb); /*这句语句挺有问题,要是该指数项唯有Pb才有呢,相加后依然链接到Pb的内存空间上 */
}
void MultiPolyn(polynomial Pa,polynomial Pb,polynomial Pc) /*乘法运算,分解为一系列的加法运算*/
{
LinkList qa=Pa->next;
LinkList qb=Pb->next;
// LinkList qc=Pc;
LinkList head;
LinkList qd;
LinkList t[20],d[20],h[20];/*,s1,s2; 这些结构体指针数组所对应的空间也应该为它们加个指数值为负一的内存! 有啊!!!*/
int i,j;
//float product;
/******下面添加的这两句由于思考疏忽耗费了我大半个月的精力********/
Pc->coef=0.0;
Pc->expn=-1;
Pc->next=NULL;
/******以上*********/
while(qa&&qb)
{
for(j=0;j<20;j++)
{
d[j]=(LinkList)malloc(sizeof(term));
// if(!d[j]) exit(OVERFLOW);
d[j]->coef=0.0;
d[j]->expn=-1;
d[j]->next=NULL;
h[j]=d[j];
qd=qa;
for(i=0;i<20;i++) /*二维数组应该有两个中括号吧? 不,不用,用了指针 */
{
//leave it alone!
t[i]=(LinkList)malloc(sizeof(term));
// if(!t[i]) exit(OVERFLOW);
*t[i]=*qd;
t[i]->coef=(qd->coef)*(qb->coef)*(-1);
t[i]->expn=qd->expn+qb->expn;
d[j]->next=t[i];
d[j]=t[i];
qd=qd->next;
if(!qd)
{
d[j]->next=NULL;
break;
}
}
qb=qb->next;
if(!qb)
{
h[j+1]=NULL;
break;
}
}
}
//printPolyn(h[0]);
//printPolyn(h[1]);
//printPolyn(h[2]);
//printPolyn(h[3]);
/*非常奇怪,加了这两句就可以运行乘法了,不过打印出来的却是相反数,而且返回值不是0,而是3221225477
//现在不用那个特殊加法也可以了!?难道是因为我创建的那伪二维数组实现了地址的复用???
测试发现,如果碰到空地址,比如这个h[3],会进入一段时间死循环。。。果不其然
//自己应该是在指针的理解上出现了一些问题,得去攻读下o'reilly的《深入理解c指针》了 */
//Not effective???
for(j=0;j<20;j++) //对了,每一列指数值不一定相同的吖!
{
if(!h[j+1]) //原来是你把我辛辛苦苦生成的结果的头指针给改了的#.#
{
head=h[j];
break; //不,不是它的错,是下面的Pc->next出现了两个-1指数项!
}
// printPolyn(h[j+1]);
AddPolyn_multi(h[j+1],h[j]);
head=h[j+1];
}
// qc->next=qa?qa:qb;
Pc->next=head; //擦!你丫蛋没初始化就跑进来了
//free(Pb); /*乘法部分逻辑上是没什么问题的咯,问题应该是出现在构造加法那里,哪里没有接上 */
} //(后来补充)看来不是构造加法问题
void diff(polynomial Pa, polynomial Pb)
{
LinkList qa=Pa->next;
LinkList head;
Pb->coef=0.0;
Pb->expn=-1;
Pb->next=NULL;
head=Pb;
// Pb=Pb->next;
while(qa)
{
Pb->next=(LinkList)malloc(sizeof(term));
// if(!Pb->next) exit(OVERFLOW);
Pb=Pb->next;
Pb->coef=(qa->coef)*(float)(qa->expn); //coef和expn类型不同,需要进行类型转化
Pb->expn=qa->expn-1;
Pb->next=NULL;
qa=qa->next;
}
Pb=head;
}
int main()
{
polynomial Pa;
polynomial Pb;
polynomial Pc;
polynomial Pd;
Pa=(LinkList)malloc(sizeof(term));
Pb=(LinkList)malloc(sizeof(term));
Pc=(LinkList)malloc(sizeof(term));
// Pc->next=NULL;
Pd=(LinkList)malloc(sizeof(term));
// Pd->next=NULL;
CreatePolyn(Pa);
printf("Pa=");
printPolyn(Pa);
CreatePolyn(Pb);
printf("Pb=");
printPolyn(Pb);
/* Pc = Pa;
Pd = Pb;
*/
printf("\nPa'=");
diff(Pa,Pc);
printPolyn(Pc);
printf("Pa+Pb=");
AddPolyn(Pa,Pb,Pc);
printPolyn(Pc);
printf("Pa-Pb=");
SubPolyn(Pa,Pb,Pc);
printPolyn(Pc);
printf("Pa*Pb=");
MultiPolyn(Pa,Pb,Pd);
printPolyn(Pd);
// printf("\n");
/* printf("Pb'=");
diff(Pb,Pc);
printPolyn(Pc);
*/
return 0;
实现代码(纯净版):
#include<stdio.h>
#include<stdlib.h>
typedef struct term{
float coef;
int expn;
struct term *next;
}term,*LinkList;
typedef LinkList polynomial;
int cmp(LinkList pa,LinkList pb)
{
if(pa->expn > pb->expn)
return 1;
else if(pa->expn == pb->expn)
return 0;
else
return -1;
}
int LocateElem(LinkList L,LinkList t,LinkList *q)
{
LinkList p1=L->next;
LinkList p2=L;
while(p1)
{
if(t->expn > p1->expn)
{
p1=p1->next;
p2=p2->next;
}
else if(t->expn == p1->expn)
{
*q=p1;
return 1;
}
else
{
*q=p2;
return 0;
}
}
*q=p2;
return 0;
}
void CreatePolyn(polynomial P)
{
LinkList t;
LinkList q;
P->coef=0.0;
P->expn=-1;
P->next=NULL;
printf("Please input coefficient and exponent in format like 1,2 and end with 0,0 :\n");
t=(LinkList)malloc(sizeof(term));
t->next=NULL;
scanf("%f,%d",&t->coef,&t->expn);
while(t->coef||t->expn)
{
if(!LocateElem(P,t,&q))
{
t->next=q->next;
q->next=t;
}
t=(LinkList)malloc(sizeof(term));
t->next=NULL;
scanf("%f,%d",&t->coef,&t->expn);
}
}
void printPolyn(polynomial P)
{
LinkList q;
q=P->next;
if(!q)
{
printf("0\n");
}
while(q)
{
if(q->coef==0)
{
printf("");
q=q->next;
}
if(q->expn==0)
{
printf("%.2f",q->coef);
q=q->next;
}
else if(q->expn>0)
{
printf("%.2f*x^%d",q->coef,q->expn);
q=q->next;
}
else
{
printf("%.2f*x^(%d)",q->coef,q->expn);
q=q->next;
}
if(q)
{
if(q->coef>0)
printf("+");
else
printf("");
}
else
printf("\n");
}
}
void AddPolyn(polynomial Pa,polynomial Pb,polynomial Pc)
{
LinkList qa=Pa->next;
LinkList qb=Pb->next;
LinkList qc=Pc;
LinkList head=qc;
LinkList s;
float sum;
Pc->coef=0.0;
Pc->expn=-1;
Pc->next=NULL;
while(qa&&qb)
{
switch(cmp(qa,qb))
{
case -1:
s=(LinkList)malloc(sizeof(term));
*s=*qa;
qc->next=s;
qc=s;
qa=qa->next;
break;
case 0:
sum=qa->coef+qb->coef;
if(sum!=0.0)
{
s=(LinkList)malloc(sizeof(term));
*s=*qa;
s->coef=sum;
qc->next=s;
qc=s;
qa=qa->next;
qb=qb->next;
}
else
{
qc->next=qa->next;
qa=qa->next;
qb=qb->next;
}
break;
case 1:
s=(LinkList)malloc(sizeof(term));
*s=*qb;
qc->next=s;
qc=s;
qb=qb->next;
break;
}
}
qc->next=qa?qa:qb;
Pc=head;
}
void SubPolyn(polynomial Pa,polynomial Pb,polynomial Pc)
{
LinkList qa=Pa->next;
LinkList qb=Pb->next;
LinkList qc=Pc;
LinkList head=qc;
LinkList s;
float differ;
Pc->coef=0.0;
Pc->expn=-1;
Pc->next=NULL;
while(qb)
{
qb->coef=0-(qb->coef);
qb=qb->next;
}
qb=Pb->next;
while(qa&&qb)
{
switch(cmp(qa,qb))
{
case -1:
s=(LinkList)malloc(sizeof(term));
*s=*qa;
qc->next=s;
qc=s;
qa=qa->next;
break;
case 0:
differ=qa->coef+qb->coef;
if(differ!=0.0)
{
s=(LinkList)malloc(sizeof(term));
*s=*qa;
s->coef=differ;
qc->next=s;
qc=s;
qa=qa->next;
qb=qb->next;
}
else
{
qc->next=qa->next;
qa=qa->next;
qb=qb->next;
}
break;
case 1:
s=(LinkList)malloc(sizeof(term));
*s=*qb;
qc->next=s;
qc=s;
qb=qb->next;
break;
}
}
qc->next=qa?qa:qb;
Pc=head;
}
void diff(polynomial Pa,polynomial Pb)
{
LinkList qa=Pa->next;
LinkList head;
Pb->coef=0.0;
Pb->expn=-1;
Pb->next=NULL;
head=Pb;
while(qa)
{
Pb->next=(LinkList)malloc(sizeof(term));
Pb=Pb->next;
Pb->coef=(qa->coef)*(float)(qa->expn);
Pb->expn=qa->expn-1;
Pb->next=NULL;
qa=qa->next;
}
Pb=head;
}
void AddPolyn_multi(polynomial Pa,polynomial Pb)
{
LinkList qa=Pa->next;
LinkList qb=Pb->next;
LinkList qc=qa;
LinkList head=qc;
LinkList s,s1,s2;
float sum;
while(qa&&qb)
{
switch(cmp(qa,qb))
{
case -1:
qc->next=qa;
qc=qa;
qa=qa->next;
break;
case 0:
sum=qa->coef+qb->coef;
if(sum!=0.0)
{
s=qb;
qa->coef=sum;
qc->next=qa;
qc=qa;
qa=qa->next;
qb=qb->next;
free(s);
}
else
{
s1=qa;
s2=qb;
qc->next=qa->next;
qa=qa->next;
qb=qb->next;
free(s1);
free(s2);
}
break;
case 1:
qc->next=qb;
qc=qb;
qb=qb->next;
break;
}
}
qc->next=qa?qa:qb;
Pa=head;
}
void MultiPolyn(polynomial Pa,polynomial Pb,polynomial Pc)
{
LinkList qa=Pa->next;
LinkList qb=Pb->next;
LinkList head;
LinkList qd;
LinkList t[20],d[20],h[20];
int i,j;
Pc->coef=0.0;
Pc->expn=-1;
Pc->next=NULL;
while(qa&&qb)
{
for(j=0;j<20;j++)
{
d[j]=(LinkList)malloc(sizeof(term));
d[j]->coef=0.0;
d[j]->expn=-1;
d[j]->next=NULL;
h[j]=d[j];
qd=qa;
for(i=0;i<20;i++)
{
t[i]=(LinkList)malloc(sizeof(term));
*t[i]=*qd;
t[i]->coef=(qd->coef)*(qb->coef)*(-1);
t[i]->expn=qd->expn+qb->expn;
d[j]->next=t[i];
d[j]=t[i];
qd=qd->next;
if(!qd)
{
d[j]->next=NULL;
break;
}
}
qb=qb->next;
if(!qb)
{
h[j+1]=NULL;
break;
}
}
}
for(j=0;j<20;j++)
{
if(!h[j+1])
{
head=h[j];
break;
}
AddPolyn_multi(h[j+1],h[j]);
head=h[j+1];
}
Pc->next=head;
}
int main()
{
polynomial Pa;
polynomial Pb;
polynomial Pc;
polynomial Pd;
Pa=(LinkList)malloc(sizeof(term));
Pb=(LinkList)malloc(sizeof(term));
Pc=(LinkList)malloc(sizeof(term));
Pd=(LinkList)malloc(sizeof(term));
CreatePolyn(Pa);
printf("Pa=");
printPolyn(Pa);
CreatePolyn(Pb);
printf("Pb=");
printPolyn(Pb);
printf("\nPa'=");
diff(Pa,Pc);
printPolyn(Pc);
printf("Pa+Pb=");
AddPolyn(Pa,Pb,Pc);
printPolyn(Pc);
printf("Pa-Pb=");
SubPolyn(Pa,Pb,Pc);
printPolyn(Pc);
printf("Pa*Pb=");
MultiPolyn(Pa,Pb,Pd);
printPolyn(Pd);
return 0;
}
运行结果:
参考文章:
利用单链表实现一元多项式的表示及相加
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。