多项式的乘积与和
本题目来源于https://pintia.cn/
题目描述
设计函数分别求两个一元多项式的乘积与和。
输入格式
输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
输出格式
输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。
输入样例
4 3 4 -5 2 6 1 -2 0
3 5 20 -7 4 3 1
输出样例
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
本文采用了4中方式解决该问题,这四种方式其实遵循的算法是一样的,只是每种方式采用了不同的数据存储结构。
对于这个问题,比较核心的算法是处理两式相乘的思路,主要有两种:
逐次插入法:
- L1的第一项分别于L2各项相乘,得到一个结果式L
- L1其余各项分别于L2各项相乘,保存相乘结果c和e
- 根据结果指数e寻找应该插入到L的位置
- 若该位置的指数小于e,则将节点插入到该位置之前
- 若该位置的指数等于e,判断该位置的系数与c之和是否为0
- 为0则删除该节点
- 不为0则将该节点的系数进行更新
乘法转换为加法:(算法一的方法二采用该思想)
- 创建一个结果式子L,再创建一个临时式子tmp
- tmp用于存放每次L1一项与L2各项相乘的结果
- L1每完成一项的相乘,就将L和tmp做一次加法运算
算法一:采用链表进行存储
方法一:自定链表操作
这种方式是遵循MOOC上浙大数据结构给出的方式,虽然在程序中使用了C++的语法,但是设计思想还是C语言的思想,采用传统的定义链表节点的方式存储数据。这种方式适合练习链表的使用,相关操作包含了链表的插入,查找,删除操作。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
//定义数据结构
typedef struct Node* Poly;
struct Node{
int coef;
int expon;
Poly next;
};
//读取数据
Poly Read()
{
int n;
cin >> n;
Poly Head = (Poly)malloc(sizeof(struct Node));
Poly p = Head;
while(n--)
{
int tmp1,tmp2;
cin >> tmp1 >> tmp2;
if(tmp1 != 0) //对于零多项式,不将其输入到链表中
{
Poly tmp = (Poly)malloc(sizeof(struct Node));
tmp->coef = tmp1;
tmp->expon = tmp2;
p->next = tmp;
p = p->next;
}
}
p->next = NULL; //数据输入完成后需要将链表的尾指针置空
return Head;
}
//多项式相乘
Poly Multiply(Poly L1,Poly L2)
{
if(L1->next == NULL) //如果存在0多项式,则两个多项式相乘返回的是0,即返回自身
return L1;
if(L2->next == NULL)
return L2;
Poly Head = (Poly)malloc(sizeof(struct Node));
Poly p = Head;
Poly p1 = L1->next;
Poly p2 = L2->next;
while(p2)
{
//先生成一个结果链表,L1的第一项分别于L2的各项相乘
Poly tmp = (Poly)malloc(sizeof(struct Node));
int c = p1->coef * p2->coef;
int e = p1->expon + p2->expon;
tmp->coef = c;
tmp->expon = e;
p->next = tmp;
p = p->next;
p2 = p2->next;
}
p->next = NULL; //生成结果链表后要将尾指针置空,因为后面的操作不只是简单的插入了
p1 = p1->next;
while(p1)
{
p2 = L2->next;
p = Head;
while(p2)
{
int c = p1->coef * p2->coef;
int e = p1->expon + p2->expon;
//寻找符合条件的插入位置,该条件为指数不能大于前面的元素
while(p->next && p->next->expon > e)
p = p->next;
//找到插入位置后,如果该位置的指数恰好为e,则要进行系数合并;若小于e,则进行节点插入
if(p->next && p->next->expon == e)
{
//如果系数之和不为0,则更新链表中的系数;为0则删除该节点
if(c + p->next->coef != 0)
p->next->coef += c;
else
{
Poly tmp = p->next;
p->next = tmp->next;
free(tmp);
}
}
else
{
Poly tmp = (Poly)malloc(sizeof(struct Node));
tmp->coef = c;
tmp->expon = e;
tmp->next = p->next;
p->next = tmp;
}
p2 = p2->next;
}
p1 = p1->next;
}
return Head;
}
//多项式相加
Poly Sum(Poly L1,Poly L2)
{
if(L1->next == NULL) //如果存在零多项式,则两式相加,返回另一个多项式
return L2;
if(L2->next == NULL)
return L1;
Poly Head = (Poly)malloc(sizeof(struct Node));
Poly p = Head;
Poly p1 = L1->next;
Poly p2 = L2->next;
while(p1 && p2)
{
if(p1->expon > p2->expon)
{
Poly tmp = (Poly)malloc(sizeof(struct Node));
tmp->coef = p1->coef;
tmp->expon = p1->expon;
p->next = tmp;
p = p->next;
p1 = p1->next;
}
else if(p1->expon < p2->expon)
{
Poly tmp = (Poly)malloc(sizeof(struct Node));
tmp->coef = p2->coef;
tmp->expon = p2->expon;
p->next = tmp;
p = p->next;
p2 = p2->next;
}
else
{
int sum = p1->coef + p2->coef;
if(sum != 0)
{
Poly tmp = (Poly)malloc(sizeof(struct Node));
tmp->coef = sum;
tmp->expon = p1->expon;
p->next = tmp;
p = p->next;
}
p1 = p1->next;
p2 = p2->next;
}
}
while(p1)
{
Poly tmp = (Poly)malloc(sizeof(struct Node));
tmp->coef = p1->coef;
tmp->expon = p1->expon;
p->next = tmp;
p = p->next;
p1 = p1->next;
}
while(p2)
{
Poly tmp = (Poly)malloc(sizeof(struct Node));
tmp->coef = p2->coef;
tmp->expon = p2->expon;
p->next = tmp;
p = p->next;
p2 = p2->next;
}
p->next = NULL;
return Head;
}
//输出多项式结果
void Print(Poly L)
{
if(L->next == NULL)
cout << 0 << " " << 0 << endl;
else
{
Poly p = L->next;
while(p)
{
if(p->next == NULL)
cout << p->coef << " " << p->expon;
else
cout << p->coef << " " << p->expon << " ";
p = p->next;
}
cout << endl;
}
}
int main()
{
Poly L1 = Read();
Poly L2 = Read();
Poly L3 = Multiply(L1,L2);
Poly L4 = Sum(L1,L2);
Print(L3);
Print(L4);
}
方法二:使用List容器
这里使用的是C++的list容器,并且采用了将乘法转变为加法的思想。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef struct Node Poly;
struct Node{
int coef;
int expon;
};
list<Poly> Read()
{
int n;
cin >> n;
list<Poly> L;
while(n--)
{
int tmp1,tmp2;
cin >> tmp1 >> tmp2;
if(tmp1 != 0)
{
Poly tmp;
tmp.coef = tmp1;
tmp.expon = tmp2;
L.push_back(tmp);
}
}
return L;
}
list<Poly> Sum(list<Poly> L1,list<Poly> L2)
{
if(L1.begin() == L1.end())
return L2;
if(L2.begin() == L2.end())
return L1;
list<Poly> L;
auto it1 = L1.begin();
auto it2 = L2.begin();
while(it1 != L1.end() && it2 != L2.end())
{
if(it1->expon > it2->expon)
{
L.push_back(*it1);
it1++;
}
else if(it1->expon < it2->expon)
{
L.push_back(*it2);
it2++;
}
else
{
int tmp = it1->coef + it2->coef;
if(tmp != 0)
{
Poly t;
t.coef = tmp;
t.expon = it1->expon;
L.push_back(t);
}
it1++;
it2++;
}
}
while(it1 != L1.end())
{
L.push_back(*it1);
it1++;
}
while(it2 != L2.end())
{
L.push_back(*it2);
it2++;
}
return L;
}
list<Poly> Multiply(list<Poly> L1,list<Poly> L2)
{
if(L1.begin() == L1.end())
return L1;
if(L2.begin() == L2.end())
return L2;
list<Poly> L;
for(auto it1 = L1.begin();it1 != L1.end();it1++)
{
list<Poly> tmp;
for(auto it2 = L2.begin();it2 != L2.end();it2++)
{
int c = (it1->coef) * (it2->coef);
int e = (it1->expon) + (it2->expon);
Poly t;
t.coef = c;
t.expon = e;
if(c != 0)
tmp.push_back(t);
}
L = Sum(L,tmp);
}
return L;
}
void Print(list<Poly> L)
{
if(L.begin() == L.end())
cout << 0 << " " << 0;
else
{
for(auto it = L.begin();it != L.end();it++)
{
if(it == L.begin())
cout << it->coef << " " << it->expon;
else
cout << " " << it->coef << " " << it->expon;
}
}
cout << endl;
}
int main()
{
list<Poly> L1 = Read();
list<Poly> L2 = Read();
list<Poly> L3 = Multiply(L1,L2);
list<Poly> L4 = Sum(L1,L2);
Print(L3);
Print(L4);
return 0;
}
算法二:采用动态数组存储
这里采用的方式是动态数组,使用了C++的vector容器。这里主要是对容器进行初始化操作,每次进行操作都是作为对象进行的。采用这种方式的好处是可以直接使用vector的一些模板函数,简化编程。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef struct node LNode;
//相当于构建了LNode类
struct node{
int coef;
int expon;
};
vector<LNode> Read()
{
int n;
cin >> n;
vector<LNode> L;
while(n--)
{
int tmp1,tmp2;
cin >> tmp1 >> tmp2;
if(tmp1 != 0)
{
LNode tmp;
tmp.coef = tmp1;
tmp.expon = tmp2;
L.push_back(tmp);
}
}
return L;
}
vector<LNode> Multiply(vector<LNode> L1,vector<LNode> L2)
{
if(L1.begin() == L1.end())
return L1;
if(L2.begin() == L2.end())
return L2;
vector<LNode> L;
auto it1 = L1.begin();
for(auto it2 = L2.begin();it2 != L2.end();it2++)
{
int c = (*it1).coef * (*it2).coef;
int e = (*it1).expon + (*it2).expon;
LNode tmp;
tmp.coef = c;
tmp.expon = e;
L.push_back(tmp);
}
if(it1 != L1.end())
it1++;
else return L;
for(;it1 != L1.end();it1++)
{
for(auto it2 = L2.begin();it2 != L2.end();it2++)
{
auto it = L.begin();
int c = (*it1).coef * (*it2).coef;
int e = (*it1).expon + (*it2).expon;
while((*it).expon > e && it < L.end())
it++;
if(it == L.end())
{
LNode tmp;
tmp.coef = c;
tmp.expon = e;
L.push_back(tmp);
}
else
{
if((*it).expon == e)
{
if((*it).coef + c != 0)
it->coef += c;
else
{
L.erase(it);
}
}
else
{
LNode tmp;
tmp.coef = c;
tmp.expon = e;
L.insert(it,tmp);
}
}
}
}
return L;
}
vector<LNode> Sum(vector<LNode> L1,vector<LNode> L2)
{
if(L1.begin() == L1.end())
return L2;
if(L2.begin() == L2.end())
return L1;
vector<LNode> L;
auto it1 = L1.begin();
auto it2 = L2.begin();
while(it1 != L1.end() && it2 != L2.end())
{
if((*it1).expon > (*it2).expon)
{
L.push_back(*it1);
it1++;
}
else if((*it1).expon < (*it2).expon)
{
L.push_back(*it2);
it2++;
}
else
{
if((*it1).coef + (*it2).coef != 0)
{
LNode tmp;
tmp.coef = (*it1).coef + (*it2).coef;
tmp.expon = (*it1).expon;
L.push_back(tmp);
}
it1++;
it2++;
}
}
while(it1 != L1.end())
{
L.push_back(*it1);
it1++;
}
while(it2 != L2.end())
{
L.push_back(*it2);
it2++;
}
return L;
}
void Print(vector<LNode> L)
{
if(L.begin() == L.end())
{
cout << 0 << " " << 0;
}
else
{
for(auto it = L.begin();it != L.end();it++)
{
if(it == L.begin())
cout << (*it).coef << " " << (*it).expon;
else
cout << " " << (*it).coef << " " << (*it).expon;
}
}
cout << endl;
}
int main()
{
vector<LNode> L1 = Read();
vector<LNode> L2 = Read();
vector<LNode> L3 = Multiply(L1,L2);
vector<LNode> L4 = Sum(L1,L2);
Print(L3);
Print(L4);
return 0;
}
算法三:采用map容器存储
这个采用的是C++的map容器.其实map容器和unordered_map容器在使用上是一致的,所以也可以采用unordered_map来实现。他们的区别在于map底层由红黑树支持的,而后者使用哈希表支持的。此题采用map时存储顺序有些变化,为<expon,coef>.这样存的好处在于指数是唯一的,正好符合map的键唯一的特性。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
map<int,int> Read()
{
int n;
cin >> n;
map<int,int> M;
while(n--)
{
int tmp1,tmp2;
cin >> tmp1 >> tmp2;
if(tmp1 != 0)
M.insert(pair<int,int>(tmp2,tmp1));
}
return M;
}
map<int,int> Multiply(map<int,int> M1,map<int,int> M2)
{
if(M1.begin() == M1.end())
return M1;
if(M2.begin() == M2.end())
return M2;
map<int,int> M;
auto it1 = M1.begin();
auto it2 = M2.begin();
while(it2 != M2.end())
{
auto c = (it1->second) * (it2->second);
auto e = (it1->first) + (it2->first);
if(c != 0)
M.insert(pair<int,int>(e,c));
it2++;
}
it1++;
while(it1 != M1.end())
{
it2 = M2.begin();
while(it2 != M2.end())
{
auto c = (it1->second) * (it2->second);
auto e = (it1->first) + (it2->first);
auto it = M.find(e); //寻找map中是否已存储了e
if(it != M.end())
{ //已存储了就执行判断语句
//如果相加后系数为0,则删掉该键值对
if((it->second) + c == 0)
M.erase(it);
else //如果不为0,则更新该系数
(it->second) += c;
}
else //未找到键为e的键值对,就直接插入
M.insert(pair<int,int>(e,c));
it2++;
}
it1++;
}
return M;
}
map<int,int> Sum(map<int,int> M1,map<int,int> M2)
{
if(M1.begin() == M1.end())
return M2;
if(M2.begin() == M2.end())
return M1;
auto it1 = M1.begin();
auto it2 = M2.begin();
map<int,int> M;
//直接将L1复制到结果式中
while(it1 != M1.end())
{
int c = it1->second;
int e = it1->first;
M.insert(pair<int,int>(e,c));
it1++;
}
//将L2存入结果式中时,需要判断式中是否已有对应的指数,若存在,则要进行同类项合并,检查结果是否为0
//不存在则插入
while(it2 != M2.end())
{
int e = it2->first;
int c = it2->second;
auto tmp = M.find(e);
if(tmp == M.end())
M.insert(pair<int,int>(e,c));
else
{
int t = tmp->second;
if(t + c == 0)
M.erase(tmp);
else
tmp->second += c;
}
it2++;
}
return M;
}
void Print(map<int,int> M)
{
if(M.begin() == M.end())
cout << 0 << " " << 0;
else
{
for(auto it = M.rbegin();it != M.rend();it++)
{
//map中的迭代器不支持it+1之类的操作,所以输出方式进行一下调整
//map中的数据是按照键值升序排列的,而此题要求降序输出,所以使用反向迭代器实现
if(it == M.rbegin())
cout << it->second << " " << it->first;
else
cout << " " << it->second << " " << it->first;
}
}
cout << endl;
}
int main()
{
map<int,int> M1 = Read();
map<int,int> M2 = Read();
map<int,int> M3 = Multiply(M1,M2);
map<int,int> M4 = Sum(M1,M2);
Print(M3);
Print(M4);
return 0;
}