目录
一、要求
① 输入:从键盘输入多项式的各项系数和指数,创建一元多项式;
② 输出:按给定格式输出一元多项式;(例如:3*x^20-x^7+10)
③ 多项式加法: 任意输入另一个多项式,输出其与原多项式的和。
④ 多项式减法: 任意输入另一个多项式,将其作为减数输出其与原多项式的差。
⑤ 多项式乘法: 任意输入另一个多项式,输出其与原多项式的积。
二、算法分析
1. 存储结构
顺序和链式实现遍历和查找操作的效率没用区别,但在做元素插入操作时链式结构效率较高。
我们要求进行加法减法乘法运算,那么就要不停进行插入(计算后加入链表)删除(计算后释放不需要的空间),所以我们采取链式结构
2. 每个功能的详细分析
1)定义结构体
typedef struct pnode //定义结构体
{
float xishu; //系数
int zhishu; //指数
struct pnode *next; //指针
}pnode,*polynomial; //结构体名字
这个结构体有数据域和指针域两部分,数据域包括系数和指数
2)自定义初始化链表函数
其实这一部分可以省略,但是当程序太大时,我们就可以不用写太多重复步骤,直接调用初始化链表函数,给链表初始化
int InitList(polynomial &L) //初始化指针函数,便于后面初始化操作
{
L=new pnode; //为创建的链表自动分配空间
L->next=NULL; //创建头结点,其next域置为NULL
return 0;
}
链表增加头结点的作用:
* 便于首元结点的处理
增加了头结点后,首元结点的地=地址保存在头结点(即其“前驱”结点)的指针域中,则对链表第一个数据元素的操作与其它数据元素相同,无需进行特殊处理。
* 便于空表和非空表的统一处理
3)创建链表
void CreatePolyn(polynomial &p,int n) //创建链表函数,需要传入创建的链表参数以及项数
{
polynomial s,pre,q; //创建s,pre,q三个结构体
cout<<"请输入对应系数和指数:"<<endl;
for(int i=1;i<=n;++i) //做循环,直到达到链表的项数结束循环
{
s=new pnode; //为s动态分配空间
cin>>s->xishu>>s->zhishu; //输入要创建的链表的系数和指数
pre=p; //pre用于保存q的前驱,初值为头结点
q=p->next; //q初始化,指向首元结点
while(q&&q->zhishu<s->zhishu) //比较指数,找到第一个大于输入项指数的项*q
{
pre=q;
q=q->next;
}
s->next=q; //将输入项s插入到q和它的前驱结点pre之间
pre->next=s;
}
}
具体过程,举个例子,画图如下:
假设我要创建2x^2+3x^0+4x^5这一组链表
首先,在主函数中对引用的链表p进行初始化,给头结点
在这个函数中给s分配空间,并且输入系数和指数
然后对p和s中的两个指数进行大小判断(也就是为了让输入的链表按指数大小,从小到大依次显示),p中为空,空不小于2,所以跳过循环,直接将s插入p中
注意,插入操作,先将s指向q,再让q的前驱pre指向s,这里就解释了为什么需要pre和q指针了
接着插入后的p如下,给s分配空间,并且输入系数和指数,然后对p和s中的两个指数进行大小判断(也就是为了让输入的链表按指数大小,从小到大依次显示),p中为2,2不小于0,所以跳过循环,直接将s插入p中
同理,p如下,继续给s分配空间,并且输入系数和指数,然后对p和s中的两个指数进行大小判断(也就是为了让输入的链表按指数大小,从小到大依次显示),p中为0,0小于5,所以执行循环,pre和q指针都后移;接着判断,p中为2,2小于5,所以执行循环,pre和q指针都后移;接着判断,p中为空,空不小于5,所以跳过循环,直接将s插入p中
最后,p链表创建ok
4) 输出结果
输出:按给定格式输出一元多项式;(例如:3*x^20-x^7+10)
分析:我们要解决的有三个问题,系数为1,-1,其它;指数为1,0,其它;符号显示
为了符号能够正确显示,我们可以把首元结点提出来单独分析系数和指数问题,然后剩下的结点带入循环进行系数指数判断,这样就能解决符号显示。(因为我们发现单纯输出+,-时,要前面多符号,要么后面多,再者就是显示+-5)
void Print(polynomial &p) //输出结果多项式
{
pnode *q; //用一个指针指向需要输出的链表
q=p->next; //指向它的首元结点
if(q->xishu==1) //后面三个id,else if,else主要是为了解决符号显示问题
{
if(q->zhishu==1)
{
cout<<"x";
}
else if(q->zhishu==0)
{
cout<<1;
}
else
{
cout<<"x^"<<q->zhishu;
}
}
else if(q->xishu==-1)
{
if(q->zhishu==1)
{
cout<<"-x";
}
else if(q->zhishu==0)
{
cout<<-1;
}
else
{
cout<<"-x^"<<q->zhishu;
}
}
else
{
if(q->zhishu==1)
{
cout<<q->xishu<<"x";
}
else if(q->zhishu==0)
{
cout<<q->xishu;
}
else
{
cout<<q->xishu<<"*x^"<<q->zhishu;
}
}
q=q->next; //让指针指向首元结点的下一个结点,后面的就只需要做一个循环解决系数和指数问题
while(q) //当q存在时
{
if(q->xishu==1) //如果系数为1,指数为1,0,其它数
{
if(q->zhishu==1)
{
cout<<"+x";
}
else if(q->zhishu==0)
{
cout<<"+1";
}
else
{
cout<<"+x^"<<q->zhishu;
}
}
else if(q->xishu==-1) //如果系数为-1,指数为1,0,其它数
{
if(q->zhishu==1)
{
cout<<"-x";
}
else if(q->zhishu==0)
{
cout<<"-1";
}
else
{
cout<<"-x^"<<q->zhishu;
}
}
else //如果系数为其它,指数>0,<0并且等于1或0的情况,为了解决符号以及显示
{
if(q->xishu>0)
{
if(q->zhishu==1)
{
cout<<"+"<<q->xishu<<"x";
}
else if(q->zhishu==0)
{
cout<<"+"<<q->xishu;
}
else
{
cout<<"+"<<q->xishu<<"*x^"<<q->zhishu;
}
}
else
{
if(q->zhishu==1)
{
cout<<q->xishu<<"x";
}
else if(q->zhishu==0)
{
cout<<q->xishu;
}
else
{
cout<<q->xishu<<"*x^"<<q->zhishu;
}
}
}
q=q->next; //指针再移动到下一个结点
}
}
这里因为有系数指数都需要自由组合,所以进行的if判断有很多,目前没用想到其它更优化的办法
5)加法运算
pa=pa+pb
思路:
* 指针p1,p2初始化,分别指向pa,pb首元结点
* p3指向和多项式的当前结点,初值为pa的头结点
* 当指针p1和p2均未到达表尾时,则循环比较p1和p2所指结点对应的指数值。有以下三种情况(用sum保存系数和)
--当p1指数大于p2指数时。系数相加,如果和不为0,p1系数的值改为sum,同时删除p2结点;
若和为0,同时删除p1和p2结点
--当p1指数小于p2指数时。让p1结点在p3后面,p1后移,再继续判断
--反之,当p1指数大于p2指数时。让p2结点在p3后面,p2后移,再继续判断
* 当两两判断完后,肯定会有一项单独露出来,那么那一项就是指数最大的,只需要将它插入到p3所指结点的后面
* 释放pb
void AddPolyn(polynomial &pa,polynomial &pb) //pa=pa+pb,最终保留在pa中
{
int sum; //用于保存指数相同时,系数相加后的结果
polynomial p1,p2,p3,r; //p1指向pa,p2指向pb,p3指向当前结点,初值为pa,r用于保存计算后需要释放的p2结点
p1=pa->next;
p2=pb->next;
p3=pa;
while(p1&&p2) //当p1,p2存在时
{
if(p1->zhishu==p2->zhishu) //进行判断,如果p1的指数和p2的指数相同,那么系数相加,用sum保存结果
{
sum=p1->xishu+p2->xishu;
if(sum!=0) //对sum保存的系数进行判断。不等于0时
{
p1->xishu=sum; //修改pa当前结点的系数值为两项系数的和
p3->next=p1; //将修改后的pa结点加在p3之后,p3指向p1,p1指向后一项
p3=p1;
p1=p1->next;
r=p2; //删除pb当前结点,p2指向后一项
p2=p2->next;
delete r;
}
else //如果系数和为0,则删除当前pa,pb结点
{
r=p1;
p1=p1->next;
delete r;
r=p2;
p2=p2->next;
delete r;
}
}
else if(p1->zhishu<p2->zhishu) //如果pa结点指数小于pb结点指数
{
p3->next=p1; //p1的结点放在p3后面
p3=p1; //p3指向p1,p1指向后一项
p1=p1->next;
}
else //如果pa结点指数大于pb结点指数
{
p3->next=p2; //p2的结点放在p3后面
p3=p2; //p3指向p2,p2指向后一项
p2=p2->next;
}
}
p3->next=p1?p1:p2; //当循环结束时,p1,p2一定会剩下一项,让剩下的插入pa(p3指向)
delete pb; //释放pb
}
6) 减法运算
pa=pa-pb
思路与加法类似,但是需要注意减法之后的符号问题,pb余留的符号问题
void SubPolyn(polynomial &pa,polynomial &pb) pa=pa-pb,最终保留在pa中
{
int sum; //用于保存指数相同时,系数相减后的结果
polynomial p1,p2,p3,r; //p1指向pa,p2指向pb,p3指向当前结点,初值为pa,r用于保存计算后需要释放的p2结点
p1=pa->next;
p2=pb->next;
p3=pa;
while(p1&&p2) //当p1,p2存在时
{
if(p1->zhishu==p2->zhishu) //进行判断,如果p1的指数和p2的指数相同,那么系数相减,用sum保存结果
{
sum=p1->xishu-p2->xishu;
if(sum!=0) //对sum保存的系数进行判断。不等于0时
{
p1->xishu=sum; //修改pa当前结点的系数值为两项系数的差
p3->next=p1; //将修改后的pa结点加在p3之后,p3指向p1,p1指向后一项
p3=p1;
p1=p1->next;
r=p2; //删除pb当前结点,p2指向后一项
p2=p2->next;
delete r;
}
else //如果系数和为0,则删除当前pa,pb结点
{
r=p1;
p1=p1->next;
delete r;
r=p2;
p2=p2->next;
delete r;
}
}
else if(p1->zhishu<p2->zhishu) //如果pa结点指数小于pb结点指数
{
p3->next=p1; //p1的结点放在p3后面
p3=p1; //p3指向p1,p1指向后一项
p1=p1->next;
}
else //如果pa结点指数大于pb结点指数
{
p2->xishu=0-p2->xishu; //p2的结点放在p3后面,注意应该变成负的
p3->next=p2; //p3指向p2,p2指向后一项
p3=p2;
p2=p2->next;
}
}
if(p3->next=p1) //如果剩余段是p1
{//插入非空多项式的剩余段
p3->next=p1;
}
else //如果剩余段是p2
{
p3->next=p2;
while(p2)//第二段连上要变成负的
{
p2->xishu=0-p2->xishu;
p2=p2->next;
}
}
delete pb; //释放pb
}
7)乘法运算
pc=pa*pb
思路:
* 指针p1,p2初始化,分别指向pa,pb首元结点
* p3指向pc的当前结点,并且创建一个头结点
* 当指针p1和p2均未到达表尾时,则循环比较p1和p2所指结点对应的指数值。
* 释放pb
注意:
p1=pa->next;
pc->next=NULL的先后位置
这里要这样理解,pc相当于覆盖pa位置,不停在pa的链表结点刷新,如果位置变成
pc->next=NULL;p1=pa->next;那么pa就会有两个头结点,指针做运算就不能指向第一个元素(首元结点)
void MultiplyPolyn(polynomial pa,polynomial pb,polynomial &pc) //pc=pa*pb
{
pc=pa; //pc指向pa头结点
polynomial p1,p2,p3,p; //p1指向pa首元结点,p2指向pb首元结点
p1=pa->next;
pc->next=NULL; //给pc设置头结点
int sum; //保存指数相加的结果
for(;p1;p1=p1->next) //给p1的每一个结点做循环
{
for(p2=pb->next;p2;p2=p2->next) //给p2的每一个结点做循环
{
p3=pc; //p3指向当前结点,初值为pc
sum=p1->zhishu+p2->zhishu; //保存指数相加的结果
while(p3->next&&p3->next->zhishu<sum) //当p3存在,并且指数小于计算的,p3后移
{
p3=p3->next;
}
if(p3->next&&p3->next->zhishu==sum) //当p3存在,并且指数等于计算的,p3系数加上计算的系数
{
p3->next->xishu+=(p1->xishu*p2->xishu);
}
else //否则将计算后的结果插入p3
{
p=new pnode;
p->zhishu=sum;
p->xishu=p1->xishu*p2->xishu;
p->next=p3->next;
p3->next=p;
}
}
}
delete pb; //释放pb
Print(pc); //将pc打印出来
}
三、代码实现
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>
using namespace std;
typedef struct pnode //定义结构体
{
float xishu; //系数
int zhishu; //指数
struct pnode *next; //指针
}pnode,*polynomial; //结构体名字
int InitList(polynomial &L) //初始化指针函数,便于后面初始化操作
{
L=new pnode; //为创建的链表自动分配空间
L->next=NULL; //创建头结点,其next域置为NULL
return 0;
}
void CreatePolyn(polynomial &p,int n) //创建链表函数,需要传入创建的链表参数以及项数
{
polynomial s,pre,q; //创建s,pre,q三个结构体
cout<<"请输入对应系数和指数:"<<endl;
for(int i=1;i<=n;++i) //做循环,直到达到链表的项数结束循环
{
s=new pnode; //为s动态分配空间
cin>>s->xishu>>s->zhishu; //输入要创建的链表的系数和指数
pre=p; //pre用于保存q的前驱,初值为头结点
q=p->next; //q初始化,指向首元结点
while(q&&q->zhishu<s->zhishu) //比较指数,找到第一个大于输入项指数的项*q
{
pre=q;
q=q->next;
}
s->next=q; //将输入项s插入到q和它的前驱结点pre之间
pre->next=s;
}
}
void Print(polynomial &p) //输出结果多项式
{
pnode *q; //用一个指针指向需要输出的链表
q=p->next; //指向它的首元结点
if(q->xishu==1) //后面三个id,else if,else主要是为了解决符号显示问题
{
if(q->zhishu==1)
{
cout<<"x";
}
else if(q->zhishu==0)
{
cout<<1;
}
else
{
cout<<"x^"<<q->zhishu;
}
}
else if(q->xishu==-1)
{
if(q->zhishu==1)
{
cout<<"-x";
}
else if(q->zhishu==0)
{
cout<<-1;
}
else
{
cout<<"-x^"<<q->zhishu;
}
}
else
{
if(q->zhishu==1)
{
cout<<q->xishu<<"x";
}
else if(q->zhishu==0)
{
cout<<q->xishu;
}
else
{
cout<<q->xishu<<"*x^"<<q->zhishu;
}
}
q=q->next; //让指针指向首元结点的下一个结点,后面的就只需要做一个循环解决系数和指数问题
while(q) //当q存在时
{
if(q->xishu==1) //如果系数为1,指数为1,0,其它数
{
if(q->zhishu==1)
{
cout<<"+x";
}
else if(q->zhishu==0)
{
cout<<"+1";
}
else
{
cout<<"+x^"<<q->zhishu;
}
}
else if(q->xishu==-1) //如果系数为-1,指数为1,0,其它数
{
if(q->zhishu==1)
{
cout<<"-x";
}
else if(q->zhishu==0)
{
cout<<"-1";
}
else
{
cout<<"-x^"<<q->zhishu;
}
}
else //如果系数为其它,指数>0,<0并且等于1或0的情况,为了解决符号以及显示
{
if(q->xishu>0)
{
if(q->zhishu==1)
{
cout<<"+"<<q->xishu<<"x";
}
else if(q->zhishu==0)
{
cout<<"+"<<q->xishu;
}
else
{
cout<<"+"<<q->xishu<<"*x^"<<q->zhishu;
}
}
else
{
if(q->zhishu==1)
{
cout<<q->xishu<<"x";
}
else if(q->zhishu==0)
{
cout<<q->xishu;
}
else
{
cout<<q->xishu<<"*x^"<<q->zhishu;
}
}
}
q=q->next; //指针再移动到下一个结点
}
}
void AddPolyn(polynomial &pa,polynomial &pb) //pa=pa+pb,最终保留在pa中
{
int sum; //用于保存指数相同时,系数相加后的结果
polynomial p1,p2,p3,r; //p1指向pa,p2指向pb,p3指向当前结点,初值为pa,r用于保存计算后需要释放的p2结点
p1=pa->next;
p2=pb->next;
p3=pa;
while(p1&&p2) //当p1,p2存在时
{
if(p1->zhishu==p2->zhishu) //进行判断,如果p1的指数和p2的指数相同,那么系数相加,用sum保存结果
{
sum=p1->xishu+p2->xishu;
if(sum!=0) //对sum保存的系数进行判断。不等于0时
{
p1->xishu=sum; //修改pa当前结点的系数值为两项系数的和
p3->next=p1; //将修改后的pa结点加在p3之后,p3指向p1,p1指向后一项
p3=p1;
p1=p1->next;
r=p2; //删除pb当前结点,p2指向后一项
p2=p2->next;
delete r;
}
else //如果系数和为0,则删除当前pa,pb结点
{
r=p1;
p1=p1->next;
delete r;
r=p2;
p2=p2->next;
delete r;
}
}
else if(p1->zhishu<p2->zhishu) //如果pa结点指数小于pb结点指数
{
p3->next=p1; //p1的结点放在p3后面
p3=p1; //p3指向p1,p1指向后一项
p1=p1->next;
}
else //如果pa结点指数大于pb结点指数
{
p3->next=p2; //p2的结点放在p3后面
p3=p2; //p3指向p2,p2指向后一项
p2=p2->next;
}
}
p3->next=p1?p1:p2; //当循环结束时,p1,p2一定会剩下一项,让剩下的插入pa(p3指向)
delete pb; //释放pb
}
void SubPolyn(polynomial &pa,polynomial &pb) pa=pa-pb,最终保留在pa中
{
int sum; //用于保存指数相同时,系数相减后的结果
polynomial p1,p2,p3,r; //p1指向pa,p2指向pb,p3指向当前结点,初值为pa,r用于保存计算后需要释放的p2结点
p1=pa->next;
p2=pb->next;
p3=pa;
while(p1&&p2) //当p1,p2存在时
{
if(p1->zhishu==p2->zhishu) //进行判断,如果p1的指数和p2的指数相同,那么系数相减,用sum保存结果
{
sum=p1->xishu-p2->xishu;
if(sum!=0) //对sum保存的系数进行判断。不等于0时
{
p1->xishu=sum; //修改pa当前结点的系数值为两项系数的差
p3->next=p1; //将修改后的pa结点加在p3之后,p3指向p1,p1指向后一项
p3=p1;
p1=p1->next;
r=p2; //删除pb当前结点,p2指向后一项
p2=p2->next;
delete r;
}
else //如果系数和为0,则删除当前pa,pb结点
{
r=p1;
p1=p1->next;
delete r;
r=p2;
p2=p2->next;
delete r;
}
}
else if(p1->zhishu<p2->zhishu) //如果pa结点指数小于pb结点指数
{
p3->next=p1; //p1的结点放在p3后面
p3=p1; //p3指向p1,p1指向后一项
p1=p1->next;
}
else //如果pa结点指数大于pb结点指数
{
p2->xishu=0-p2->xishu; //p2的结点放在p3后面,注意应该变成负的
p3->next=p2; //p3指向p2,p2指向后一项
p3=p2;
p2=p2->next;
}
}
if(p3->next==p1) //如果剩余段是p1
{//插入非空多项式的剩余段
p3->next=p1;
}
else //如果剩余段是p2
{
p3->next=p2;
while(p2)//第二段连上要变成负的
{
p2->xishu=0-p2->xishu;
p2=p2->next;
}
}
delete pb; //释放pb
}
void MultiplyPolyn(polynomial pa,polynomial pb,polynomial &pc) //pc=pa*pb
{
pc=pa; //pc指向pa头结点
polynomial p1,p2,p3,p; //p1指向pa首元结点,p2指向pb首元结点
// p1=pa->next;
pc->next=NULL; //给pc设置头结点
int sum; //保存指数相加的结果
for(p1=pa->next;p1;p1=p1->next) //给p1的每一个结点做循环
{
for(p2=pb->next;p2;p2=p2->next) //给p2的每一个结点做循环
{
p3=pc; //p3指向当前结点,初值为pc
sum=p1->zhishu+p2->zhishu; //保存指数相加的结果
while(p3->next&&p3->next->zhishu<sum) //当p3存在,并且指数小于计算的,p3后移
{
p3=p3->next;
}
if(p3->next&&p3->next->zhishu==sum) //当p3存在,并且指数等于计算的,p3系数加上计算的系数
{
p3->next->xishu+=(p1->xishu*p2->xishu);
}
else //否则将计算后的结果插入p3
{
p=new pnode;
p->zhishu=sum;
p->xishu=p1->xishu*p2->xishu;
p->next=p3->next;
p3->next=p;
}
}
}
delete pb; //释放pb
Print(pc); //将pc打印出来
}
int main()
{
polynomial pa;
InitList(pa); //初始化pa
polynomial pb;
InitList(pb); //初始化pb
polynomial pc;
InitList(pc); //初始化pc
int n;
cout<<"请输入pa的项数:"<<endl;
cin>>n;
CreatePolyn(pa,n);
Print(pa);
cout<<endl;
int m;
cout<<"请输入pb的项数:"<<endl;
cin>>m;
CreatePolyn(pb,m);
Print(pb);
cout<<endl;
cout<<" --------------------------\n";
cout<<"| 请输入运算符:+或-或* |"<<endl;
cout<<" --------------------------"<<endl;
string f;
cin>>f;
if(f=="+")
{
AddPolyn(pa,pb);
cout<<"相加的结果为:";
Print(pa);
cout<<endl;
}
if(f=="-")
{
SubPolyn(pa,pb);
cout<<"相减的结果为:";
Print(pa);
cout<<endl;
}
if(f=="*")
{
cout<<"相乘的结果为:";
MultiplyPolyn(pa,pb,pc);
cout<<endl;
}
return 0;
}
四、测试
选用1*x^0+1*x^1+2*x^3和-1*x^0-2*x^3分别做加法、减法、乘法运算
1. 加法
2. 减法
3. 乘法