目录
这篇文章是我开始系统学习算法时为记录学习过程写的,比较适合小白,大佬请跳过。不当之处请大家批评指正。
题目描述
题目:
采用链表形式,求两个一元多项式的乘积:h3 = h1*h2。函数原型为:void multiplication( NODE * h1, NODE * h2, NODE * h3 )。
输入:
输入数据为两行,分别表示两个一元多项式。每个一元多项式以指数递增的顺序输入多项式各项的系数(整数)、指数(整数)。
例如:1+2x+x2表示为:<1,0>,<2,1>,<1,2>,
输出:
以指数递增的顺序输出乘积: <系数,指数>,<系数,指数>,<系数,指数>,
零多项式的输出格式为:<0,0>,
前置代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{ int coef, exp;
struct node *next;
} NODE;
void multiplication( NODE *, NODE * , NODE * );
void input( NODE * );
void output( NODE * );
void input( NODE * head )
{ int flag, sign, sum, x;
char c;
NODE * p = head;
while ( (c=getchar()) !='\n' )
{
if ( c == '<' )
{ sum = 0;
sign = 1;
flag = 1;
}
else if ( c =='-' )
sign = -1;
else if( c >='0'&& c <='9' )
{ sum = sum*10 + c - '0';
}
else if ( c == ',' )
{ if ( flag == 1 )
{ x = sign * sum;
sum = 0;
flag = 2;
sign = 1;
}
}
else if ( c == '>' )
{ p->next = ( NODE * ) malloc( sizeof(NODE) );
p->next->coef = x;
p->next->exp = sign * sum;
p = p->next;
p->next = NULL;
flag = 0;
}
}
}
void output( NODE * head )
{
while ( head->next != NULL )
{ head = head->next;
printf("<%d,%d>,", head->coef, head->exp );
}
printf("\n");
}
int main()
{ NODE * head1, * head2, * head3;
head1 = ( NODE * ) malloc( sizeof(NODE) );
input( head1 );
head2 = ( NODE * ) malloc( sizeof(NODE) );
input( head2 );
head3 = ( NODE * ) malloc( sizeof(NODE) );
head3->next = NULL;
multiplication( head1, head2, head3 );
output( head3 );
return 0;
}
问题分析
分析前置代码:
头部代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct node //定义结构体
{ int coef, exp; //定义整型系数和指数
struct node *next; //指向下一个结构体的指针
} NODE;
main函数:
int main()
{ NODE * head1, * head2, * head3;
head1 = ( NODE * ) malloc( sizeof(NODE) );
input( head1 ); //建立第一个多项式的链表
head2 = ( NODE * ) malloc( sizeof(NODE) );
input( head2 ); //建立第二个多项式的链表
head3 = ( NODE * ) malloc( sizeof(NODE) );
head3->next = NULL; //建立第三个多项式的空链表
multiplication( head1, head2, head3 ); //计算前两个多项式的乘积,并填入第三个多项式
output( head3 ); //输出第三个多项式
return 0;
}
子函数:
1、建立多项式链表的函数
void input( NODE * head ) //建立多项式链表
{ int flag, sign, sum, x;
char c;
NODE * p = head;
while ( (c=getchar()) !='\n' )
{
if ( c == '<' ) //左括号,做相应标记
{ sum = 0;
sign = 1;
flag = 1;
}
else if ( c =='-' ) //遇到符号的时候系数要乘-1
sign = -1;
else if( c >='0'&& c <='9' ) //系数不一定是一位数,有可能是多位,注意乘10
{ sum = sum*10 + c - '0';
}
else if ( c == ',' ) //逗号,做相应标记
{ if ( flag == 1 ) //如果是逗号右边的数,代表指数
{ x = sign * sum;
sum = 0;
flag = 2;
sign = 1;
}
}
else if ( c == '>' ) //右括号,做相应标记
{ p->next = ( NODE * ) malloc( sizeof(NODE) );
p->next->coef = x; //把系数赋给结构体对应成员
p->next->exp = sign * sum; //把指数赋给结构体对应成员
p = p->next; //移动指针
p->next = NULL;
flag = 0; //重置标志量
}
}
}
2、输出函数:
void output( NODE * head ) //输出多项式的各项
{
while ( head->next != NULL )
{ head = head->next; //移动头指针
printf("<%d,%d>,", head->coef, head->exp ); //输出各项
}
printf("\n");
}
解题方法
一元多项式的乘法:
我们需要编写的是多项式1和多项式2相乘之后的结果,并将其赋到多项式3中。
由多项式乘法的计算规律,我们可以想到,多项式1和多项式2的每一项都要两两相乘一次。
其中有一些项的指数可能会重复。我们需要把指数相同的项的系数合并。然后还要注意按指数由小到大的顺序排列各项。
有了这个思路,我们可以设计如下代码:
void multiplication( NODE *head1, NODE *head2 , NODE *head3 )
{
int ind,k,flag=0;
NODE *p,*q,*r,*t,*m,*ss,*tem;
p=(NODE*)malloc(sizeof(NODE));
q=(NODE*)malloc(sizeof(NODE));
r=(NODE*)malloc(sizeof(NODE));
t=(NODE*)malloc(sizeof(NODE));
tem=(NODE*)malloc(sizeof(NODE));
p=head1; //p为多项式1的移动指针,最开始指向多项式1头部
q=head2; //q为多项式2的移动指针,最开始指向多项式2头部
r=head3->next; //r为多项式3的移动指针,最开始指向多项式3的第一个元素
t=head3; //t为多项式3的移动指针,最开始指向多项式3的头部
tem=head3->next; //tem为多项式3的移动指针,用来记录上一轮乘出来的元素
//放到多项式3的哪个位置了,如果这次的指数大于上次该位置的指数,
//直接从该位置往后找,节省时间
while(p->next!=NULL) //当p的下一个不为空时,往后遍历
{
p=p->next;
q=head2; //每次大层循环(多项式1)更新一项时,多项式2都从第一项开始遍历
tem=head3->next; //tem初始化
while(q->next!=NULL) //当q的下一个不为空时,往后遍历
{
q=q->next;
k=(p->coef)*(q->coef); //计算当前两项相乘的系数
ind=(p->exp)+(q->exp); //计算当前两项相乘的指数
if(k==0) //如果系数为0,直接跳过该轮
{
continue;
}
m=(NODE*)malloc(sizeof(NODE)); //否则,建立一个结构体变量存储该项
m->coef=k;
m->exp=ind;
if(r!=NULL) //当多项式3中有元素时
{
if(tem!=NULL&&(m->exp)>(tem->exp))
{
t=tem; //看一下上一轮tem所指元素的指数是否小于该轮元素的指数
r=t->next; //如果是,那么直接让r从tem后开始遍历,找到
//多项式3中合适的插入位置,节省时间!!
}
}
while(r!=NULL) //如果上一轮tem所指元素的指数大于该轮元素的指数,则没法省时
{ //r从第一个元素开始遍历
if(r->exp==ind) //如果该元素指数和多项式3中某项指数相等,则将该元素系数
{ //加到多项式3中这项系数上
r->coef+=k;
if(r->coef==0) //判断一下加完后的系数是否为0,若为0,则在
{ //多项式3中删除该项
t->next=r->next;
r=t->next;
}
r=head3->next; //重置r指针和t指针
t=head3;
flag=1; //设置标志量,证明已经处理完该新元素
break; //立刻退出
}
else if(r->exp<ind) //若该元素指数小于多项式3中某项指数,则往后遍历
{
r=r->next; //后移r指针和t指针
t=t->next;
tem=t; //tem和t指针看齐
}
else if(r->exp>ind) //若该元素指数大于多项式3中某项指数
{ //说明该元素项要插到r指针前t指针后
m->next=r;
t->next=m;
r=head3->next; //插入后重置r指针和t指针
t=head3;
flag=1; //设置标志量,证明已经处理完该新元素
break; //立刻退出
}
}
if(flag==0) //如果标志量未变化,说明该元素项的指数大于了多项式3中所有项的指数
{ //此时要将该元素项插到多项式3的最后
m->next=r;
t->next=m;
tem=t;
r=head3->next; //加入后重置r指针和t指针
t=head3;
}
flag=0; //标志项重置
}
}
if(head3->next==NULL) //如果最后多项式3中一项也没有(说明系数全为0,都被删除了)
{
ss=(NODE*)malloc(sizeof(NODE)); //此时需要将<0,0>放入多项式3中
head3->next=ss;
ss->next=NULL;
ss->coef=0;
ss->exp=0;
}
}
一元多项式的加法
拓展一下一元多项式的加法:
伪代码:
建立多项式1的移动指针p; 置于多项式1头部。
建立多项式2的移动指针q; 置于多项式2头部。
当p->next不为空时
{
p=p->next;
如果q->next不为空
{
q=q->next;
比较p->next->exp和q->next->exp
如果相等,就把q->next->coef加到p->next->coef上
如果小于,就后移p
如果大于,就把q插到p前面
}
}
检查操作后的多项式1,把系数为0的项删掉
检查删完后的多项式1,若为空,加入<0,0>
返回多项式1头指针
总结
解决多项式乘法问题时我们需要注意,插入每一项的位置都要使多项式3满足指数从小到大排列。
为了不超时,我们还设置了一个tem指针记录上一轮插入多项式3的元素的位置,如果下一轮要插入的元素的指数大于tem所指元素的指数,则直接让r从tem的下一个元素开始遍历即可。
对于加法来说,只需要把其中一个多项式看做基体,合并即可,不需要另建一个多项式。