问题描述:
第一种算法:顺序存储结构实现——顺序表
(1)算法思路:
算法要实现两个一元多项式相关的相关运算,相加、相减、相乘。首先我们要选取一种存储结构来存放我们多项式的每一项,我们可以采用顺序存储结构中的顺序表来实现多项式的存储。用一个数组a存储多项式的相关数据:数组分量a[i]表示项 X^i前的系数,用数组分量下标对应相应项的指数,我们的数组分量值就是对应这一项的系数。
例如,f(x)=6+8X+2X2+6*X5,可以用一个顺序表来表示:
这种方法在一般情况下对一元多项式实现相关运算是比较方便的。我们顺序表实现两个一元多项式的相加,只要把两个数组的对应分量相加就行了,代码很容易实现,同理多项式的减法也较容易实现。实现两个一元多项式的乘法,我们首先选定一个多项式,让它的每一项另一个多项式的每一项依次相乘,乘完后用一个临时顺序表来保存得到的结果,将得到的所有临时顺序表相加起来就是两个多项式相乘的结果。
但是用顺序表来实现也存在重大的问题,就是在多项式比较稀疏的情况下(多项式有较高的阶,但是只有很少的非零项。),算法的时间和空间效率比较差。例如: f(x)=1+2X+3X^3000,表示这个多项式的顺序表要采用一个大小至少为3001的数组,但是这个数组中的大部分数据为0,只有3项不为零,空间浪费严重。而且我们要遍历这个存储多项式的顺序表,要遍历3001次,时间复杂度较高。这主要是顺序表实现该算法的缺点。
(2)算法代码:
#include<stdio.h>
#include<stdlib.h>
#define maxsize 100
typedef struct node {
int a[maxsize];
int length;
} list;
//初始化顺序表
list* creat_list()
{
struct node* L;
L = (list*)malloc(sizeof(struct node));
L->length = 0;
return L;
}
void input(list* L)//一元多项式的输入
{
int i;
printf("请输入此多项式的项数:");
scanf("%d", &L->length);
for (i = 0; i < L->length; i++)
{
printf("请输入此多项式X^%d项的系数: ", i);
scanf("%d", &L->a[i]);
}
printf("\n");
}
void output(struct node* L) //一元多项式的输出
{
int i, t = 0;
for (i = L->length - 1; i >= 0; i--)
{
if (L->a[i] == 0)
{
t++;
continue;
}
else
{
if (i == 0)
{
if (L->a[i] < 0)
printf("%d", L->a[i]);
else
printf("+%d", L->a[i]);
}
else if (0 < i && i < L->length - 1)
{
if (i == 1)
{
if (L->a[i] < 0)
printf("%d*X", L->a[i]);
else
printf("+%d*X", L->a[i]);
}
else
{
if (L->a[i] < 0)
printf("%d*X^%d", L->a[i], i);
else
printf("+%d*X^%d", L->a[i], i);
}
}
else if (i == L->length - 1)
{
if (i == 1)
{
printf("%d*X", L->a[i]);
}
else
printf("%d*X^%d", L->a[i], i);
}
}
}
if (t == L->length)
{
printf("0\n");
}
printf("\n");
}
list* sum(list* L1, list* L2) //实现两个一元多项式的相加操作
{
int i, h;
struct node* p;
list* L3;
L3 = creat_list();
if (L1->length <= L2->length)
{
p = L1;
h = L2->length - L1->length;
}
else
{
p = L2;
h = L1->length - L2->length;
}
for (i = 0; i < p->length; i++)
{
L3->a[i] = L1->a[i] + L2->a[i];
L3->length++;
}
if (h != 0)
{
if (p == L1)
{
for (i = L1->length; i <= L2->length - 1; i++)
{
L3->a[i] = L2->a[i];
L3->length++;
}
}
else
for (i = L2->length; i <= L1->length - 1; i++)
{
L3->a[i] = L1->a[i];
L3->length++;
}
}
return L3;
}
list* poor(list* L1, list* L2)//实现两个一元多项式的相减操作
{
int i, h;
struct node* p;
list* L;
L = creat_list();
h = L1->length - L2->length;
if (h <= 0)
{
p = L1;
}
else
{
p = L2;
}
for (i = 0; i < p->length; i++)
{
L->a[i] = L1->a[i] - L2->a[i];
L->length++;
}
if (h != 0)
{
if (p == L2)
{
for (i = L2->length; i <= L1->length - 1; i++)
{
L->a[i] = L1->a[i];
L->length++;
}
}
if (p == L1)
{
for (i = L1->length; i <= L2->length - 1; i++)
{
L->a[i] = -1 * (L2->a[i]);
L->length++;
}
}
}
return L;
}
list* multiply(list* L1, list* L2) //实现两个多项式的相乘
{
int i, j, k;
list* L;
L = creat_list();
for (i = 0; i <= L1->length - 1; i++)
{
list* p = creat_list();
p->length = i + L2->length;
for (k = 0; k <= p->length - 1; k++)
{
p->a[k] = 0;
}
for (j = 0; j <= L2->length - 1; j++)
{
p->a[i + j] = L1->a[i] * L2->a[j];
}
L = sum(L, p);
}
return L;
}
void show()
{
printf("\t\t 指令集合\n");
printf("\n\t1 《《《《《 一元多项式的加法运算\n");
printf("\n\t2 《《《《《 一元多项式的减法运算\n");
printf("\n\t3 《《《《《 一元多项式的乘法运算\n");
}
void main()
{
int i, h;
list* P;
list* L[2];
for (i = 0; i < 2; i++)
{
L[i] = creat_list();
printf("\t请输入第%d个一元多项式\n", i + 1);
input(L[i]);
printf("第%d个一元多项式的表达式为:\n", i + 1);
printf("\tF%d(X)=", i + 1);
output(L[i]);
printf("\n\n");
}
show();
printf("请对两个多项式选择相关运算指令:\n");
scanf("%d", &h);
switch (h)
{
case 1:
P = sum(L[0], L[1]);
printf("两个一元多项式的和为:\n\tF3(X)=");
output(P);
break;
case 2:
printf("两个一元多项式的差为:\n\tF3(X)=");
P = poor(L[0], L[1]);
output(P);
break;
case 3:
printf("两个一元多项式的乘积为:\n\tF3(X)=");
P = multiply(L[0], L[1]);
output(P);
break;
default:
printf("指令错误!\n");
}
}
(3)代码运行结果:
加法运算:
减法运算:
乘法运算:
(4)代码分析:
从(2)中代码可以看出,实现一元多项式的加,减和乘运算的函数的时间复杂度为O(N2),所以我们整体算法的时间复杂度为:O(N2)。但是这种算法存在重大的问题,就是在多项式比较稀疏的情况下(多项式有较高的阶,但是只有很少的非零项。),算法的时间和空间效率比较差。例如: f(x)=1+2X+3X^3000,表示这个多项式的顺序表要采用一个大小至少为3001的数组,但是这个数组中的大部分数据为0,只有3项不为零,空间浪费严重。当我们要遍历这个存储多项式的顺序表,要遍历3001次,时间复杂度较高。当一元多项式中项中X的的指数过大时,算法的性能较差。
顺序存储结构—— 算法改进思路
在多项式比较稀疏的情况下(多项式有较高的阶,但是只有很少的非零项。)算法的时间和空间效率比较差,我们打算对其进行改进,我们主要提出了其改进思路。
采用顺序存储结构来表示一元多项式的非零项,多项式的每一项都有两个信息,系数和指数,因此我们可以用一个结构体数组来表示我们一元多项式,结构体数组的每一项表示一元多项式的一个非零项。数组的大小可以根据非零项的最多个数来确定,而并不是根据多项式的最高阶来确定。这种方法。对于稀疏多项式的情况下能够节省大量的空间。但是多项式并不是很稀疏,则节省空间的优势就没有了,反而会导致运算过于复杂。例如,我们用这种方法实现两个一元多项式的相加操作的具体过程为:首先我们应该对这两个多项式按指数对多项式进行排列(按指数依次大到小排列多项式的每一项),之后从头开始查看两个多项式的每一项,如果当前两项的指数不一样,则将两个多项式中指数较大的那一项给我们临时创建的结果多项式中 ;如果它们的指数一样而且对应系数和不为零,那么就将这两项的和与其指数放入到我们的结果多项式中。这种方法的运算较为复杂,而且用数组表示多项式的灵活性也不高。更进一步的解决方案就是利用 链式存储结构——单链表 来表示我们的多项式效果会更好,更具有灵活性。
第二种算法:链式存储结构实现——单链表
1)算法实现思路:
实现两个一元多项式相关的相关运算,相加、相减、相乘。可以选取链表来存放多项式的每一项的两项数据,每一次输入数据时向系统申请分配存储空间,每次存储只需要存放其系数和幂。两个多项式的项系数和幂分别存在两个链表中,在进行加、减、乘运算时首先找到不同链表中同类项(即幂相同的项),再进行系数的运算。例如链表A中存放数据2(系数) 1(幂),B中有一组数据5(系数) 1(幂)。在运算时我们首先需要在链表B中找到幂为1的数据,找到后用其系数进行运算,如上例中2+5=7,2-5=-3。 在进行乘法运算时依次拿出A链表中的项系数与B链表中的每一项系数依次相乘,并存放在一个新链表C中。 最后输出链表中的数据后需要释放其内存。
(2)算法代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define OK 1
#define NO 0
#define MAXSIZE 20
typedef char Excelelem;
typedef struct Node
{
int xishu;
int mi;
struct Node *next;
} LNode,*LinkList;
typedef struct
{
Excelelem name[100];
int length;
LinkList next;
} HeadList,*HeadLinkList;
LinkList Init(int *n); //函数声明
HeadLinkList HeadInit(char a[]);
LinkList FIND(LinkList Head,int s);
void ADD(HeadLinkList A,HeadLinkList B,HeadLinkList C);
void SUB(HeadLinkList A,HeadLinkList B,HeadLinkList C);
void Free(HeadLinkList Head);
void cout(HeadLinkList Head);
void MUL(HeadLinkList A,HeadLinkList B,HeadLinkList C);
int main()
{
HeadLinkList A,B,C;
int n;
A=HeadInit("A多项式");
printf("请输入%s:\n",A->name);
A->next=Init(&A->length);
B=HeadInit("B多项式");
printf("请输入%s:\n",B->name);
B->next=Init(&B->length);
C=HeadInit("C多项式");
C->next=NULL;
printf("%s+%s:\n",A->name,B->name);
ADD(A,B,C);
cout(C);
printf("%s-%s:\n",A->name,B->name);
SUB(A,B,C);
cout(C);
printf("%s*%s:\n",A->name,B->name);
MUL(A,B,C);
cout(C);
Free(A);
Free(B);
Free(C);
free(A),free(B),free(C);
return 0;
}
LinkList FIND(LinkList Head,int s)//查找链表中第一个系数大于ans的结点的前驱
{
if(Head->next == NULL || Head->next->mi > s)
return Head;
return FIND(Head->next,s);
}
LinkList Init(int *n)//初始化链表体
{
LinkList Head,p,q;
int i=0;
int a,b;
Head=NULL;
while(~scanf("%d",&a) && a!=0)
{
scanf("%d",&b);
q=(LinkList)malloc(sizeof(LNode));
q->xishu=a;
q->mi=b;
if(*n==0 || Head->mi>b) q->next=Head,Head=q;
else
{
p=FIND(Head,b);
q->next=p->next;
p->next=q;
}
*n++;
}
return Head;
}
HeadLinkList HeadInit(char *a)//初始化链表头
{
HeadLinkList Head;
Head=(HeadLinkList)malloc(sizeof(HeadList));
strcpy(Head->name,a);
Head->length=0;
return Head;
}
void ADD(HeadLinkList A,HeadLinkList B,HeadLinkList C)//多项式加法 O(n)
{
LinkList qa=A->next,qb=B->next,p,q=NULL;
Free(C);
while(qa || qb)
{
p=(LinkList)malloc(sizeof(LNode));
if(qb==NULL || qa && qa->mi<qb->mi)
{
*p=*qa;
qa=qa->next;
}
else if(qa==NULL || qb && qa->mi>qb->mi)
{
*p=*qb;
qb=qb->next;
}
else
{
p->xishu=qb->xishu+qa->xishu;
p->mi=qb->mi;
qa=qa->next;
qb=qb->next;
}
if(q==NULL) p->next=q,C->next=q=p;
else
p->next=q->next,q->next=p,q=p;
C->length++;
}
}
void SUB(HeadLinkList A,HeadLinkList B,HeadLinkList C)//多项式减法 O(n)
{
LinkList qa=A->next,qb=B->next,p,q=NULL;
Free(C);
while(qa!=NULL || qb!=NULL)
{
p=(LinkList)malloc(sizeof(LNode));
if(qb==NULL || qa && qa->mi<qb->mi)
{
*p=*qa;
qa=qa->next;
}
else if(qa==NULL || qb && qa->mi>qb->mi)
{
*p=*qb;
p->xishu*=-1;
qb=qb->next;
}
else
{
*p=*qa;
p->xishu-=qb->xishu;
qa=qa->next;
qb=qb->next;
if(p->xishu==0)
{
free(p);
continue;
}
}
if(q==NULL) p->next=q,C->next=q=p;
else
q->next=p->next,q->next=p,q=p;
C->length++;
}
}
void MUL(HeadLinkList A,HeadLinkList B,HeadLinkList C)//多项式乘法 O(n^3)
{
LinkList qa,qb,p,q;
int a,b;
Free(C);
for(qa=A->next; qa; qa=qa->next)
{
for(qb=B->next; qb; qb=qb->next)
{
a=qa->xishu*qb->xishu;
b=qa->mi+qb->mi;
if(C->length)
{
p=FIND(C->next,b);
if(p->mi == b)
p->xishu+=a;
else
{
q=(LinkList)malloc(sizeof(LNode));
q->xishu=a;
q->mi=b;
q->next=p->next;
p->next=q;
C->length++;
}
}
else
{
p=(LinkList)malloc(sizeof(LNode));
p->xishu=a;
p->mi=b;
p->next=C->next;
C->next=p;
C->length++;
}
}
}
}
void Free(HeadLinkList Head)//释放链表体内存
{
LinkList q=Head->next,p;
while (q)
{
p=q;
q=q->next;
free(p);
}
Head->length=0;
Head->next=NULL;
return ;
}
void cout(HeadLinkList Head)//将链表数据域以多项式形势输出
{
LinkList q=Head->next;
while(q)
{
if(q->xishu>0 && q!=Head->next)
printf("+");
printf("%.1dx^(%.1d)",q->xishu,q->mi);
q=q->next;
}
printf("\n");
return ;
}
**(3)代码运行结果:**
(4)代码分析:
该算法的时间复杂度为O(n²)。利用链表解决该问题的优点是处理离散程度较大的数据时(如f(x)=1+2X+3X^3000)可以大大节省空间,因为链表的存储地址不需要连续,可以根据需要动态分配空间。缺点则是在处理连续的数据时存储密度小(相比较顺序表而言)。
更多推荐