PTA 一元多项式的乘法与加法运算 思路分析及代码解析
一、前导
1. 需要掌握的知识
- 链表
- 一元多项式
2. 题目信息
- 题目来源:PTA / 拼题A
- 题目地址: 一元多项式的乘法与加法运算
二、解题思路分析
1. 题意理解
- 输入数据
4 3 4 -5 2 6 1 -2 0 //第一个一元多项式:首数字4表示多项式非零项的个数,随后以指数递降的方式,输入多项式非零项系数和指数
3 5 20 -7 4 3 1 //第二个一元多项式
- 输出数据
结尾不能有多余空格,另外,如果运算结果为0,输出 0 0
15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1 //两个多项式乘法运算的结果
5 20 -4 4 -5 2 9 1 -2 0 //两个多项式加法运算的结果
- 题意
编程进行一元多项式的乘法和加法运算并打印结果
2. 思路分析(重点)
本题锻炼链表的基本使用:创建和插入,插入函数是AC的重点
三、具体实现
1. 弯路和bug
- 通过链表存储数据和操作数据时,需要更细致一些,避免指向错误的位置
2. 代码框架(重点)
2.1 采用的数据结构
链表:解法选择了表头不存储数据
#define Null -1
typedef struct polynomial *PtrPoly;
struct polynomial //一元多项式按指数递降的方式进行存储
{
int coefficient; //系数
int exponent; //指数
PtrPoly next; //多项式的下一个非零项
};
2.2 程序主体框架
程序伪码描述
int main()
{
0.根据录入数据形成两个链表
1.将运算结果看成一个空链表,将数据逐项插入到这个空链表中
2.多项式乘法可以看做两层循环,分别执行系数相乘、指数相加
3.多项式加法较简单,若指数相等则系数相加
4.打印输出
}
2.3 各分支函数
- Insert( ) 核心函数,本题的核心就是考察’将数据插入到链表的合适位置’。对于一元多项式,插入时分为三种情况:
(1)插入数据的指数 相较 当前链表指向数据的指数 小
(2)插入数据的指数 大
(3)插入数据的指数 相等
由于是按指数递降的方式存储,当插入数据的指数较小时,说明还未找到合适位置,链表指向需要向后移动,直到满足插入数据的指数 大于等于 当前链表指向数据的指数。这里需要仔细想一下
PtrPoly Insert(PtrPoly result,PtrPoly Element)
{
PtrPoly head,tmp,a; //a 是 插入数据 Element的拷贝
head = result; //result 是运算结果,head记录链表的头元素
a=(PtrPoly)malloc(sizeof(struct polynomial));
a->coefficient=Element->coefficient;
a->exponent=Element->exponent;
a->next=NULL;
while( result->next && a->exponent < result->next->exponent ) //插入数据的指数小,执行循环。直到result->next为空 或者 插入数据的指数较大或相等
result=result->next;
if(!result->next)
{
a->next=result->next;
result->next=a;
}
else
{
if(a->exponent > result->next->exponent) //插入数据的指数大,找到位置
{
a->next=result->next;
result->next=a;
}
else if(a->exponent==result->next->exponent) //插入数据的指数相等
{
result->next->coefficient=result->next->coefficient + a->coefficient;
if(!result->next->coefficient)
{
tmp=result->next;
result->next=tmp->next;
free(tmp);
}
}
}
return head;
}
- CreatePolynomial( ) 根据录入数据存储一元多项式并形成链表。锻炼创建链表的基本功
#define Null -1
PtrPoly CreateNode() //创建一个结点
{
PtrPoly tmp;
tmp=(PtrPoly)malloc(sizeof(struct polynomial));
tmp->coefficient=Null;
tmp->exponent=Null;
tmp->next=NULL;
return tmp;
}
PtrPoly CreatePolynomial()
{
int N,coe,exp;
PtrPoly a, a_head,tmp; //typedef struct polynomial *PtrPoly;
cin>>N;
a=CreateNode(); //创建链表表头,链表表头不存储多项式的数据
a_head=a;//记录链表表头
for(int i=0;i<N;i++)
{
cin>>coe>>exp;
tmp=(PtrPoly)malloc(sizeof(struct polynomial));
tmp->coefficient=coe;
tmp->exponent=exp;
tmp->next=NULL;
a->next=tmp;
a=a->next;
}
return a_head;
}
- Multi( ) 多项式乘法运算:乘法对应两层循环;另外需要注意,由于后面还有加法运算,此时不能改变已有的多项式数据
PtrPoly Multi(PtrPoly a, PtrPoly b)
{
PtrPoly tmp,result,b_head;
tmp=CreateNode();
result=CreateNode();
a=a->next; b=b->next; b_head=b;
while(a)
{
while(b)
{
tmp->coefficient=a->coefficient * b->coefficient;
tmp->exponent=a->exponent + b->exponent;
result=Insert(result,tmp);
b=b->next;
}
a=a->next;
b=b_head;
}
return result;
}
- Add( ) 多项式加法运算:后面没有其他运算了,直接在已有的多项式数据上执行插入
PtrPoly Add(PtrPoly a, PtrPoly b)
{
b=b->next;
while(b)
{
a=Insert(a,b);
b=b->next;
}
return a;
}
- Print( ) 打印:需要考虑多项式运算结果为零的情况;另外,不要忘记数据末尾不能有多余空格
void Print(PtrPoly Poly)
{
if(!Poly->next)
{
cout<<"0 0";
return;
}
PtrPoly P=Poly;
P=P->next;
cout<<P->coefficient<<' '<<P->exponent;
while(P->next)
{
P=P->next;
cout<<' '<<P->coefficient<<' '<<P->exponent;
}
return;
}
3. 完整编码
大家如有疑问或建议,欢迎留言 😃
#include<cstdlib>
#include<iostream>
using namespace std;
#define Null -1
typedef struct polynomial *PtrPoly;
struct polynomial
{
int coefficient;
int exponent;
PtrPoly next;
};
PtrPoly Insert(PtrPoly result,PtrPoly Element);
PtrPoly CreatePolynomial();
void Print(PtrPoly Poly);
PtrPoly Add(PtrPoly a, PtrPoly b);
PtrPoly Multi(PtrPoly a, PtrPoly b);
PtrPoly CreateNode();
int main()
{
PtrPoly a,b,add,multi;
a=CreatePolynomial();
b=CreatePolynomial();
multi=Multi(a,b);
Print(multi);
cout<<endl;
add=Add(a,b);
Print(add);
return 0;
}
PtrPoly CreateNode()
{
PtrPoly tmp;
tmp=(PtrPoly)malloc(sizeof(struct polynomial));
tmp->coefficient=Null;
tmp->exponent=Null;
tmp->next=NULL;
return tmp;
}
PtrPoly Multi(PtrPoly a, PtrPoly b)
{
PtrPoly tmp,result,b_head;
tmp=CreateNode();
result=CreateNode();
a=a->next; b=b->next; b_head=b;
while(a)
{
while(b)
{
tmp->coefficient=a->coefficient * b->coefficient;
tmp->exponent=a->exponent + b->exponent;
result=Insert(result,tmp);
b=b->next;
}
a=a->next;
b=b_head;
}
return result;
}
PtrPoly Add(PtrPoly a, PtrPoly b)
{
b=b->next;
while(b)
{
a=Insert(a,b);
b=b->next;
}
return a;
}
PtrPoly Insert(PtrPoly result,PtrPoly Element)
{
PtrPoly head,tmp,a; //a 是 插入数据 Element的拷贝
head = result; //result 是运算结果,head记录链表的头元素
a=(PtrPoly)malloc(sizeof(struct polynomial));
a->coefficient=Element->coefficient;
a->exponent=Element->exponent;
a->next=NULL;
while( result->next && a->exponent < result->next->exponent ) //插入数据的指数小
result=result->next;
if(!result->next)
{
a->next=result->next;
result->next=a;
}
else
{
if(a->exponent > result->next->exponent) //插入数据的指数大,找到位置
{
a->next=result->next;
result->next=a;
}
else if(a->exponent==result->next->exponent) //插入数据的指数相等
{
result->next->coefficient=result->next->coefficient + a->coefficient;
if(!result->next->coefficient)
{
tmp=result->next;
result->next=tmp->next;
free(tmp);
}
}
}
return head;
}
PtrPoly CreatePolynomial()
{
int N,coe,exp;
PtrPoly a, a_head,tmp;
cin>>N;
a=CreateNode();
a_head=a;
for(int i=0;i<N;i++)
{
cin>>coe>>exp;
tmp=(PtrPoly)malloc(sizeof(struct polynomial));
tmp->coefficient=coe;
tmp->exponent=exp;
tmp->next=NULL;
a->next=tmp;
a=a->next;
}
return a_head;
}
void Print(PtrPoly Poly)
{
if(!Poly->next)
{
cout<<"0 0";
return;
}
PtrPoly P=Poly;
P=P->next;
cout<<P->coefficient<<' '<<P->exponent;
while(P->next)
{
P=P->next;
cout<<' '<<P->coefficient<<' '<<P->exponent;
}
return;
}
210927的AC代码:
1.进步:没有直接编码,先进行了规划;代码逻辑有比较明显的加强
2.待改进点:(1)做题速度太慢,用了差不多100分钟(2)粗心导致代码缺陷多,Debug占用了不下30分钟(3)* 最初的规划存在问题:我开始想着Add比较简单,因此 不编写Insert()函数 直接实现Add(循环两个多项式),导致重复代码多、代码量大,占用了很多时间 约30分钟。其实Insert()函数对 加法 和 乘法是通用的,优先实现Insert()才能有效缩短编码时间 (4)实现Insert()函数,需要将插入结点拷贝一份,将拷贝的结点插入,这样不会引起混乱。如果是直接插入已有结点,很容易引起指针指向混乱(代码逻辑也不好),这种情况下出现错误 Debug耗时会很长 (5)太急,希望自己40分钟内AC,因此想采用所谓最简单的方法,最终却是耗时很长的方法
#include <iostream>
using namespace std;
typedef struct Node* PtrNode;
typedef PtrNode List;
struct Node
{
int Coe; //系数
int Exp; //指数
List Next;
};
List Create(List L);
void Print(List L);
List Add(List L1, List L2);
List Multiple(List L1, List L2);
void FreeMem(List L);
int main()
{
List L1, L2, AddResult, MultipleResult;
L1 = new struct Node; L2 = new struct Node;
L1->Next = NULL; L2->Next = NULL;
L1 = Create(L1); L2 = Create(L2);
MultipleResult = Multiple(L1, L2);
Print(MultipleResult);
AddResult = Add(L1, L2);
Print(AddResult);
FreeMem(L1), FreeMem(L2), FreeMem(MultipleResult);
return 0;
}
void FreeMem(List L)
{
List tmp, Head = L;
L = L->Next;
while (L)
{
tmp = L;
L = L->Next;
delete tmp;
}
delete Head;
}
List Insert(List L, List Node)
{
List LHead = L, PreNode;
List NewNode;
NewNode = new struct Node;
NewNode->Coe = Node->Coe;
NewNode->Exp = Node->Exp;
NewNode->Next = NULL;
PreNode = L, L = L->Next;
while (L != NULL)
{
if (NewNode->Exp > L->Exp)
{
PreNode->Next = NewNode;
NewNode->Next = L;
return LHead;
}
else if(NewNode->Exp == L->Exp)
{
L->Coe = L->Coe + NewNode->Coe;
if (L->Coe == 0)
{
PreNode->Next = L->Next;
delete L, NewNode;
}
else
delete NewNode;
return LHead;
}
else
{
PreNode = L;
L = L->Next;
}
}
PreNode->Next = NewNode;
return LHead;
}
List Add(List L1, List L2) //Question 1.Code is too long! 2.Logical of Code is Right? Don't judge insert position?
{
L2 = L2->Next;
while (L2)
{
L1 = Insert(L1, L2);
L2 = L2->Next;
}
return L1;
}
List Multiple(List L1, List L2)
{
List L, L2Head = L2;
L = new struct Node; L->Next = NULL;
L1 = L1->Next;
while (L1 != NULL)
{
L2 = L2Head;
L2 = L2->Next;
while (L2 != NULL)
{
List NewNode;
NewNode = new struct Node;
NewNode->Coe = L1->Coe * L2->Coe;
NewNode->Exp = L1->Exp + L2->Exp;
NewNode->Next = NULL;
L = Insert(L, NewNode);
delete NewNode;
L2 = L2->Next;
}
L1=L1->Next;
}
return L;
}
List Create(List L)
{
List LHead = L,LNode;
int N,Coe,Exp;
cin >> N;
while (N--)
{
cin >> Coe >> Exp;
LNode = new struct Node;
LNode->Coe = Coe; LNode->Exp = Exp; LNode->Next = NULL;
L->Next = LNode; L = L->Next;
}
return LHead;
}
void Print(List L)
{
L = L->Next;
if (L != NULL)
{
cout << L->Coe << " " << L->Exp;
L = L->Next;
while (L != NULL)
{
cout<<" " << L->Coe << " " << L->Exp;
L = L->Next;
}
cout << endl;
}
else
cout << "0 0" << endl;
return;
}