第一个多项式有n项,第二个多项式有m项。以下均为最坏的情况。
操作 | 时间复杂度(T(n)) | 空间复杂度(S(n)) |
判断是否为空 | O(1) | O(1) |
得到长度 | O(n) | O(1) |
求和 | O(n+m) | O(1) |
求差 | O(n+m) | O(1) |
求积 | O(n*m) 双重循环 | O(n*m) 最坏的情况就是相乘后每一项的指数都不一样,这样就有n*m项(这种情况概率很低) |
/* 数据结构分析与学习专栏
* Copyright (c) 2015, 山东大学计算机科学与技术专业学生
* All rights reserved.
* 作 者: 高祥
* 完成日期: 2015 年 3 月 28 日
* 版 本 号:006
*任务描述:单链表的应用,模拟一元多项式的运算。
* 1:建立一元多项式 ;
* 2:打印一元多项式 ;
* 3:输出一元多项式的项数 ;
* 4:判断一元多项式是否为空 ;
* 5:一元多项式求和 ;
* 6:一元多项式求差;
* 7:一元多项式求积 ;
* 8:销毁一元多项式;
*主要函数:
* 1.InitPoly(Polynome &P);//初始化头结点
* 2.FindPoly(Polynome P,Polynome&before,Polynome &after,int expo);
//建立一元多项式的辅助函数
//参数说明:
//P是已经存在的一元多项式的头结点指针;before是满足指数小于将要插入结点指数的第一个结点指针
//after是满足指数大于等于将要插入结点指数的第一个结点指针;expo是将要插入的结点指数
//注意:before与after指针必须引用传值,达到修改CreatPoly()函数中指针的目的,且after=before->next
* 3.CreatPoly(Polynome P,int polysize);//建立一元多项式
* 4.Output(Polynome P);//输出一元多项式
* 5.int PolyLength(Polynome P);//求一元多项式的项数
* 6.Status IsEmptyPoly(Polynome P);//判断一元多项式是否为空
* 7.AddPoly(Polynome P1,Polynome&P2);//一元多项式相加,将结果赋给多项式P1
* 8.SubtractPoly(Polynome P1,Polynome&P2);//一元多项式相减,将结果赋给P1
* 9.MultiplyPoly(Polynome &P1,Polynome&P2);//一元多项式相乘,将结果赋给P1
* 10.DestroyPoly(Polynome &P);//销毁多项式
*主要优点:
1. 创建多项式:用户输入任意组由用户决定的数据(无序状态),创建的多项式是合并同类项后并且结点的指数大小依次递增(通过辅助函数FindPoly来实现该排序的功能),不多含任何一项,在合并的过程中,某些项合并后消失,那么程序接着会释放无用节点的内存达到内存最少、项数最精简的效果。
例如输入9组数据:-5 0 5 0 0 1 1 2 1 2 -2 2 -7 1 7 3 21 4
输出为:P(x)=(-7)x+(7)x^(3)+(21)x^(4)
2. 输出多项式:符合人们书写的习惯。做到了:非第一项的系数为正前面加‘+’;系数为1省略输出;常数为1不能省略输出;指数为0不输出x;指数为1不输出指数;每输出10项换行。每个数字用括号括起来是因为:当系数很大时,系统会输出如‘1.009e+098’之类的数字,为了便于识别‘+’、‘-’符号,因此每个数字均加了括号。
3. 求多项式的和差:做到了:内存最优,运算后消失的项和指数相同冗余的项均释放了内存;运算后结果依然是按照指数的升序排序。
4. 求多项式的积:同样做到了内存最优。但是没想到怎样优化时间空间复杂度,采取最笨的一项乘一项的方式,两项相乘完以后,指数、系数均可能改变,为了依然按照指数升序排列,再次使用辅助函数FindPoly来实现该排序的功能,就好像是手动输入运算后的系数和指数一样,达到排序的效果。运算结束,销毁原来的两条多项式,将结果移交给第一个头结点。
*注意:以上函数中的形参的&均是必要的,都不能去掉
*/
#include<iostream>
#include<cstdlib>
using namespace std;
#define OK 1
#define FALSE 0
#define ERROR 0
const int INF=2000000000;
typedef int Status;
typedef struct
{
double coef;
int expo;
} ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode,*LinkList;
typedef LinkList Polynome;
void InitPoly(Polynome &P);//初始化头结点
void FindPoly(Polynome P,Polynome&before,Polynome &after,int expo);//建立一元多项式的辅助函数
//参数说明:
//P是已经存在的一元多项式的头结点指针;before是满足指数小于将要插入结点指数的第一个结点指针
//after是满足指数大于等于将要插入结点指数的第一个结点指针;expo是将要插入的结点指数
//注意:before与after指针必须引用传值,达到修改CreatPoly()函数中指针的目的,且after=before->next
void CreatPoly(Polynome P,int polysize);//建立一元多项式
void Output(Polynome P);//输出一元多项式
int PolyLength(Polynome P);//求一元多项式的项数
Status IsEmptyPoly(Polynome P);//判断一元多项式是否为空
void AddPoly(Polynome P1,Polynome&P2);//一元多项式相加,将结果赋给多项式P1
void SubtractPoly(Polynome P1,Polynome&P2);//一元多项式相减,将结果赋给P1
void MultiplyPoly(Polynome &P1,Polynome&P2);//一元多项式相乘,将结果赋给P1
void DestroyPoly(Polynome &P);//销毁多项式
void Interaction();
int main()
{
Polynome P1=NULL,P2=NULL;//初始化为空指针最安全
Interaction();
int operate;
while(cin>>operate)
{
switch(operate)
{
case 0:
goto END;
case 1:
InitPoly(P1);
cout<<"请输入要创建的一元多项式的项数:";
int polysize;
cin>>polysize;
CreatPoly(P1,polysize);
break;
case 2:
Output(P1);
break;
case 3:
cout<<"该一元多项式的项数为:"<<PolyLength(P1)<<endl;
break;
case 4:
if(!IsEmptyPoly(P1))
{
cout<<"该一元多项式不为空。\n";
}
else
{
cout<<"该一元多项式为空。\n";
}
break;
case 5:
InitPoly(P2);
cout<<"请输入要创建的一元多项式的项数:";
cin>>polysize;
CreatPoly(P2,polysize);
AddPoly(P1,P2);
break;
case 6:
InitPoly(P2);
cout<<"请输入要创建的一元多项式的项数:";
cin>>polysize;
CreatPoly(P2,polysize);
SubtractPoly(P1,P2);
break;
case 7:
InitPoly(P2);
cout<<"请输入要创建的一元多项式的项数:";
cin>>polysize;
CreatPoly(P2,polysize);
MultiplyPoly(P1,P2);
break;
case 8:
DestroyPoly(P1);
cout<<"销毁一元多项式成功。进行其他操作请先创建一元多项式。\n";
break;
default:
cout<<"请输入正确的操作数!\n";
break;
}
}
END:
DestroyPoly(P1);
DestroyPoly(P2);
return 0;
}
void InitPoly(Polynome &P)//初始化头结点
{
P=(Polynome)malloc(sizeof(LNode));
P->next=NULL;
P->data.coef=0.0;//头结点的系数为0,后续所有结点的系数均不为0,
P->data.expo=-INF;//头结点的指数为负无穷,便于实现按照指数升序排列
cout<<"头结点初始化成功。\n";
}
void FindPoly(Polynome P,Polynome&before,Polynome &after,int expo)//建立一元多项式的辅助函数
//参数说明:
//P是已经存在的一元多项式的头结点指针;before是满足指数小于将要插入结点指数的第一个结点指针
//after是满足指数大于等于将要插入结点指数的第一个结点指针;expo是将要插入的结点指数
//注意:before与after指针必须引用传值,达到修改CreatPoly()函数中指针的目的,且after=before->next
{
//分类讨论:
if(!IsEmptyPoly(P))//一元多项式已经存在项
{
before=P;
after=P->next;
while(1)
{
if(before->data.expo<expo&&(after==NULL||(after&&after->data.expo>=expo)))
//after指针为空(说明要插在当前一元多项式的最后面)或者不为空且满足大小条件
{
return;
}
if(after)//after指针不为空,向后更新指针
{
before=after;
after=after->next;
}
}
}
//一元多项式为空:
before=P;
after=NULL;
}
void CreatPoly(Polynome P,int polysize)
{
cout<<"请输入"<<polysize<<"组数据,每组数据第一个数字是系数(任意非零实数),第二个数字是指数(任意整数),数字之间用空格间隔:\n";
for(int i=1; i<=polysize; i++)
{
double coef;
int expo;
cin>>coef>>expo;
if(coef)//系数为0的项不用建立
{
Polynome before,after;
FindPoly(P,before,after,expo);//找到合适位置
if(after&&after->data.expo==expo)
//若将要插入的项的指数已经存在,那么无需开辟新内存,只需要修改存在项的系数
{
after->data.coef=after->data.coef+coef;
if(after->data.coef==0)//修改后若系数为0,即该项消失,那么释放存在项的内存
{
before->next=after->next;//删除该结点,改变指针链接
free(after);
}
}
else//若将要插入的项的指数不存在,那么需开辟新内存,创建新结点
{
Polynomeq=(Polynome)malloc(sizeof(LNode));
q->data.coef=coef;
q->data.expo=expo;
before->next=q;//更新指针
q->next=after;
}
}
}
cout<<"您创建的多项式为(合并同类项后):\n";
Output(P);
}
void Output(Polynome P)//输出一元多项式
{
if(!IsEmptyPoly(P))
{
cout<<"P(x)=";
Polynome q=P->next;
int kase=0;//控制一行输出的项数和开头‘+’号的输出
while(q)
{
if(kase!=0)//不为第一项,前面填上‘+’号
{
cout<<"+";
}
if(q->data.coef>0)//系数大于0
{
if(q->data.coef!=1||(q->data.coef==1&&q->data.expo==0))//不为1的正系数或者为1的常数才输出系数
{
cout<<"("<<q->data.coef<<")";
}
}
else//系数小于0直接输出系数
{
cout<<"("<<q->data.coef<<")";
}
if(q->data.expo)//指数不为0才输出x
{
cout<<"x";
if(q->data.expo!=1)//指数为1不输出
{
cout<<"^("<<q->data.expo<<")";
}
}
kase++;//输出项+1
q=q->next;//更新指针
if(kase%10==0)//每行输出10项
{
cout<<endl;
}
}
cout<<endl;
return;
}
cout<<"多项式为空,无法输出。请先创建多项式。\n";
}
int PolyLength(Polynome P)//求一元多项式的项数
{
int num=0;
if(!IsEmptyPoly(P))
{
P=P->next;
while(P)
{
num++;
P=P->next;
}
}
return num;
}
Status IsEmptyPoly(Polynome P)//判断一元多项式是否为空
{
if(P&&P->next)
{
return FALSE;
}
return OK;
}
void AddPoly(Polynome P1,Polynome&P2)//一元多项式相加,将结果赋给多项式P1
{
if(!IsEmptyPoly(P1)&&!IsEmptyPoly(P2))//两个多项式均不为空
{
Polynome p1,p2,q,r;
p1=P1->next,p2=P2->next;//两个用来遍历的指针
q=P1;//相加后的多项式的头结点
while(p1&&p2)
{
if(p1->data.expo<p2->data.expo)//连接到P1链本身的节点
{
r=p1->next;
//预存将要访问的节点指针,因为q是P1上的指针,省去该语句后,
//语句:q->next=p1;q=p1可能会修改p1原来的指向,导致错误
q->next=p1;
q=p1;//更新指针
p1=r;
}
else if(p1->data.expo==p2->data.expo)//系数相加后连接到P1链本身的节点
{
r=p1->next;
p1->data.coef=p1->data.coef+p2->data.coef;
if(p1->data.coef==0)//合并项后消失,释放内存
{
free(p1);
}
else
{
q->next=p1;
q=p1;
}
p1=r;//更新指针
r=p2->next;
free(p2);//该结点相加后的多项式中用不到,所以释放其内存
p2=r;
}
else//连接到P2链的节点
{
r=p2->next;
q->next=p2;
q=p2;//更新指针
p2=r;
}
}
q->next= p1==NULL?p2:p1;//链接到有剩余项的链的剩余的第一个指针即可完成运算
cout<<"相加后的一元多项式为:\n";
Output(P1);
//DestroyPoly(P2);语句不能加,因为P2链的许多结点链接到了新链中,只需要释放P2链中与P1链指数相同的节点和P2的头结点
free(P2);
P2=NULL;
return;
}
cout<<"一元多项式为空,无法操作。\n";
}
void SubtractPoly(Polynome P1,Polynome&P2)//一元多项式相减,将结果赋给P1
{
if(!IsEmptyPoly(P1)&&!IsEmptyPoly(P2))//两个多项式均不为空
{
Polynome p1,p2,q,r;
p1=P1->next,p2=P2->next;//两个用来遍历的指针
q=P1;//相加后的多项式的头结点
while(p1&&p2)
{
if(p1->data.expo<p2->data.expo)//连接到P1链本身的节点
{
r=p1->next;
//预存将要访问的节点指针,因为q是P1上的指针,省去该语句后,
//语句:q->next=p1;q=p1可能会修改p1原来的指向,导致错误
q->next=p1;
q=p1;//更新指针
p1=r;
}
else if(p1->data.expo==p2->data.expo)//系数相加后连接到P1链本身的节点
{
r=p1->next;
p1->data.coef=p1->data.coef-p2->data.coef;
if(p1->data.coef==0)//合并项后消失,释放内存
{
free(p1);
}
else
{
q->next=p1;
q=p1;
}
p1=r;//更新指针
r=p2->next;
free(p2);//该结点相加后的多项式中用不到,所以释放其内存
p2=r;
}
else//连接到P2链的节点
{
p2->data.coef=-p2->data.coef;//第二个多项式的项的系数变号(被减的)
r=p2->next;
q->next=p2;
q=p2;//更新指针
p2=r;
}
}
q->next= p1==NULL?p2:p1;//链接到有剩余项的链的剩余的第一个指针即可完成运算
cout<<"相减后的一元多项式为:\n";
Output(P1);
//DestroyPoly(P2);语句不能加,因为P2链的许多结点链接到了新链中,只需要释放P2链中与P1链指数相同的节点和P2的头结点
free(P2);
P2=NULL;
return;
}
cout<<"一元多项式为空,无法操作。\n";
}
void MultiplyPoly(Polynome &P1,Polynome&P2)//一元多项式相乘,将结果赋给P1
{
if(!IsEmptyPoly(P1)&&!IsEmptyPoly(P2))
{
Polynome p1=P1->next,p2=P2->next;
Polynome P;//开辟一条新链,最后将P1的头结点指向新链
InitPoly(P);//初始化新链的头结点
//双重循环:依次用第一个多项式的每一项乘以第二个多项式的每一项,将结果项的系数和指数存起来
//视为“输入的”,采取创建一元多项式的思路,将每一组数据插入到新链中
while(p1)
{
p2=P2->next;
while(p2)
{
doublecoef=(p1->data.coef)*(p2->data.coef);//结果项的系数
intexpo=p1->data.expo+p2->data.expo;//结果项的指数
//以下同CreatPoly函数
if(coef)//系数为0的项不用建立
{
Polynome before,after;
FindPoly(P,before,after,expo);//找到合适位置
if(after&&after->data.expo==expo)
//若将要插入的项的指数已经存在,那么无需开辟新内存,只需要修改存在项的系数
{
after->data.coef=after->data.coef+coef;
if(after->data.coef==0)//修改后若系数为0,即该项消失,那么释放存在项的内存
{
before->next=after->next;//删除该结点,改变指针链接
free(after);
}
}
else//若将要插入的项的指数不存在,那么需开辟新内存,创建新结点
{
Polynomeq=(Polynome)malloc(sizeof(LNode));
q->data.coef=coef;
q->data.expo=expo;
before->next=q;//更新指针
q->next=after;
}
}
p2=p2->next;//后移指针
}
p1=p1->next;//后移指针
}
DestroyPoly(P1);//销毁两个原来的多项式
DestroyPoly(P2);
P1=P;//将结果赋给P1链
cout<<"相乘后的一元多项式为:\n";
Output(P1);
return;
}
cout<<"一元多项式为空,无法操作。\n";
}
void DestroyPoly(Polynome &P)//销毁多项式
{
while(P)
{
Polynome q=P->next;
free(P);
P=q;
}
P=NULL;
}
void Interaction()
{
cout<<"请输入对应操作的序号:\n";
cout<<"0:退出程序;\n";
cout<<"1:建立一元多项式;\n";
cout<<"2:打印一元多项式;\n";
cout<<"3:输出一元多项式的项数;\n";
cout<<"4:判断一元多项式是否为空;\n";
cout<<"5:一元多项式求和;\n";
cout<<"6:一元多项式求差;\n";
cout<<"7:一元多项式求积;\n";
cout<<"8:销毁一元多项式;\n";
}