02-线性结构2 一元多项式的乘法与加法运算 (20分)
题目
设计函数分别求两个一元多项式的乘积与和。
输入格式
输入分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
线性结构有两种实现方式,链表和数组。这里我直接用的是数组。用二维数组来存储每一项的系数和指数。关于C++实现变长数组,我使用以下方法:
int **p1 = new int*[N1];
for (int i = 0; i < N1; i++)
p1[i] = new int[2];
在不使用STL情况下,这种方法也比较容易理解。但是要注意的是,这种指针实现的数组在求数组长度时会有困难。无法使用sizeof(p1)
来求数组长度,因为指针只存储了数组的头地址,对后面有多少元素并不知道。所以为了知道相加后的项数,我定义了全局变量length,乘法也要用到。
乘法的主要思路就是把它看作加法的组合,用简单的分配律。所以应该把加法写成函数来调用。贴一下代码
#include<iostream>
using namespace std;
int length = 0;
int** add(int **p1, int **p2, int N1, int N2) {
if (p1 == NULL) {
length = N2;
int **newp2 = new int*[N2];
for (int i = 0; i < N2; i++) {
newp2[i] = new int[2];
newp2[i][0] = p2[i][0];
newp2[i][1] = p2[i][1];
}
return newp2;
}
if (p2 == NULL) {
length = N1;
int **newp1 = new int*[N1];
for (int i = 0; i < N1; i++) {
newp1[i] = new int[2];
newp1[i][0] = p1[i][0];
newp1[i][1] = p1[i][1];
}
return newp1;
}
//加法
int idx1 = 0, idx2 = 0;
int idx = 0;
int **add = new int*[N1 + N2];
for (int i = 0; i < N1 + N2; i++)
add[i] = new int[2];
while (idx1 < N1 && idx2 < N2) {
// printf("\n%d %d\n", p1[idx1][0], p2[idx2][0]);
if (p1[idx1][1] > p2[idx2][1]) { //p1指数更大
add[idx][0] = p1[idx1][0];
add[idx][1] = p1[idx1][1];
idx1++;
}
else if (p1[idx1][1] < p2[idx2][1]) { //p2指数更大
add[idx][0] = p2[idx2][0];
add[idx][1] = p2[idx2][1];
idx2++;
}
else { //指数相同,合并同类项
if(p1[idx1][0] + p2[idx2][0] == 0) {
idx1++;
idx2++;
continue;
} else {
add[idx][0] = p1[idx1][0] + p2[idx2][0];
add[idx][1] = p1[idx1][1];
idx1++;
idx2++;
}
}
idx++;
}
if (idx1 >= N1) { //p1遍历完毕
while (idx2 < N2) {
add[idx][0] = p2[idx2][0];
add[idx][1] = p2[idx2][1];
idx2++;
idx++;
}
}
else {
while (idx1 < N1) {
add[idx][0] = p1[idx1][0];
add[idx][1] = p1[idx1][1];
idx1++;
idx++;
}
}
length = idx;
//新建一个二维数组,没有空余
if (idx != 0) {
int **result = new int*[idx];
for (int i = 0; i < idx; i++) {
result[i] = new int[2];
result[i][0] = add[i][0];
result[i][1] = add[i][1];
}
return result;
}
else return NULL;
}
//两个多项式乘法
int** multiply(int **p1, int **p2, int N1, int N2) {
int **multi = NULL; // 结果
int **temp = new int*[N2];
for (int i = 0; i < N2; i++)
temp[i] = new int[2];
for (int j = 0; j < N1; j++) {
for (int i = 0; i < N2; i++) {
temp[i][0] = p1[j][0] * p2[i][0];
temp[i][1] = p1[j][1] + p2[i][1];
}
multi = add(multi, temp, length, N2);
}
return multi;
}
int main() {
int N1 = 0, N2 = 0;
// 读p1
scanf("%d", &N1);
int **p1 = new int*[N1];
for (int i = 0; i < N1; i++)
p1[i] = new int[2];
for (int i = 0; i < N1; i++) {
scanf("%d %d", &p1[i][0], &p1[i][1]);
}
// 读p2
getchar(); //读换行符
scanf("%d", &N2);
//int *p2 = new int[N2][2];
int **p2 = new int*[N2];
for (int i = 0; i < N2; i++)
p2[i] = new int[2];
for (int i = 0; i < N2; i++) {
getchar();
scanf("%d %d", &p2[i][0], &p2[i][1]);
}
if((N1==1&&p1[0][0]==0)||(N2==1&&p2[0][0]==0)){ //零多项式,不需要调用乘法函数
printf("%d %d\n", 0, 0);
}else{
//乘法
int **multiResult = multiply(p1, p2, N1, N2);
//第一行是乘法结果
if(length == 0){
printf("%d %d\n", 0, 0);
}else{
for (int i = 0; i < length; i++) {
printf("%d %d", multiResult[i][0], multiResult[i][1]);
if (i != length - 1) printf(" ");
else printf("\n");
}
}
length = 0;
}
//加法
int **addResult = add(p1, p2, N1, N2);
if(length == 0){
printf("%d %d", 0, 0);
}else{
for (int i = 0; i < length; i++) {
printf("%d %d", addResult[i][0], addResult[i][1]);
if (i != length - 1) printf(" ");
else printf("\n");
}
}
return 0;
}
还有一些要注意的地方:
- 合并同类项之后可能出现抵消的情况,这个需要在加法函数中处理,不填入数组跳过即可
- 零多项式:相乘的两个多项式若有一个为零多项式,则结果输出
0 0
。按照规则,如果一项的系数为0
,那么可以推出这一项为0 0
,进而推出此项所在多项式为零多项式。所以零多项式并不会在运算中间出现,只需要在开始处理一下即可。
然后对于此处
if (p1 == NULL) {
length = N2;
int **newp2 = new int*[N2];
for (int i = 0; i < N2; i++) {
newp2[i] = new int[2];
newp2[i][0] = p2[i][0];
newp2[i][1] = p2[i][1];
}
return newp2;
}
我开始直接返回p2,结果出现问题。原因是返回的是指针,也就是返回对某片区域的引用。而后面
multi = add(multi, temp, length, N2);
比如multi第一次的时候为空,如果按照上面的直接返回temp指针,就会使multi和temp同时指向同一片区域,那么后面temp变成新的多项式,multi会随之改变,即multi和temp的值始终相同,结果就不对。所以后来改为返回一个新的指针数组。
感觉这道题完全通过也不是很简单,有一些细节会没注意到,并且代码量也不少。不过我的代码还有一些地方可以精简的,有时间再整理一下。