mooc浙大数据结构PTA习题之一元多项式的乘法与加法运算

设计函数分别求两个一元多项式的乘积与和。

输入格式:

输入分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

参考代码(满分):

#include<iostream>
using namespace std;
struct node
{
	int coef;
	int exp;
	struct node *next;
};

void attach(int c, int e, node **rear)
{
	node *p = new node;
	p->coef = c;
	p->exp = e;
	p->next = NULL;
	(*rear)->next = p;
	*rear = p;
}
node *read()
{
	int a, c, e;
	node *rear;
	node *t;
	cin >> a;
	node *blank = new node;
	blank->next = NULL;
	rear = blank;
	while (a--)
	{
		cin >> c >> e;
		attach(c, e, &rear);
	}
	t = blank;
	blank = blank->next;
	delete t;
	return blank;
}
int compare(int a, int b)

{
	if (a > b)
		return 1;
	if (a < b)
		return 0;
	if (a == b)
		return -1;

}
node *add(node* p1, node *p2)
{
	node *front, *rear, *tt;
	front = new node;
	front->next = NULL;
	rear = front;
	int sum = 0;
	while (p1&&p2)
	{
		switch (compare(p1->exp, p2->exp))
		{
		case 1:
			attach(p1->coef, p1->exp, &rear);
			p1 = p1->next;
			break;
		case 0:
			attach(p2->coef, p2->exp, &rear);
			p2 = p2->next;
			break;
		case -1:
			sum = p1->coef + p2->coef;
			if (sum)
				attach(sum, p1->exp, &rear);
			p1 = p1->next;
			p2 = p2->next;
			break;
		}
	}
	for (; p1 != 0; p1 = p1->next)
		attach(p1->coef, p1->exp, &rear);
	for (; p2 != 0; p2 = p2->next)
		attach(p2->coef, p2->exp, &rear);
	tt = front;
	front = front->next;
	delete tt;
	return front;
}
void print(node *p)
{
	if (!p)
	{
		cout << "0 0";
		cout << endl;
		return;
	}
	int flag = 0;
	while (p)
	{
		if (!flag)

			flag = 1;

		else
			cout << " ";


		cout << p->coef << " " << p->exp;
		p = p->next;
	}
	cout << endl;
}
node *mult(node* p1, node *p2)
{
	node *front, *rear, *tt, *t1, *t2;
	front = new node;
	front->next = NULL;
	rear = front;
	int c, e;
	if (!p1 || !p2)
		return NULL;
	t1 = p1; t2 = p2;
	while (t2)
	{
		c = t1->coef*t2->coef;
		e = t1->exp + t2->exp;
		attach(c, e, &rear);
		t2 = t2->next;
	}
	t1 = t1->next;
	while (t1)
	{
		t2 = p2;
		rear = front;
		while (t2)
		{
			c = t1->coef*t2->coef;
			e = t1->exp + t2->exp;
			while ((rear->next) && (rear->next->exp > e))
				rear = rear->next;
			if ((rear->next) && (rear->next->exp == e))
			{
				if ((rear->next->coef + c) != 0)
					rear->next->coef += c;
				else
				{
					tt = rear->next;
					rear->next = tt->next;
					delete tt;
				}
			}
			else
			{
				tt = new node;
				tt->coef = c;
				tt->exp = e;
				tt->next = rear->next;
				rear->next = tt;
				rear = rear->next;

			}

			t2 = t2->next;
		}
		t1 = t1->next;
	}
	tt = front;
	front = front->next;
	delete tt;
	return front;

}
int main()
{
	node *p1, *p2, *pp, *ps;
	p1 = read();
	p2 = read();
	pp = add(p1, p2);
	ps = mult(p2, p1);
	print(ps);
	print(pp);

	return 0;
}

以上代码我敲了好久,刚开始看到题目时我是崩溃的,看了mooc后还是不懂如何实现要求的操作。大概断断续续学了两个星期吧,还是静不下心来学,其实主要是因为难以理解其中的代码。照着ppt把代码敲下来,遇到不理解的便停下思考为什么是这样,这句代码是什么意思。磕磕绊绊学了好久,上网查阅,翻书,最后那种弄明白了其中的道理的滋味实在是舒服。做一遍这道题,对建立空节点,删除增加节点有了更深的认识,而这些对于之前的我来说是极为抽象的。通过这道题我收获了许多,以下是我从0分到20分的思考过程,附上对其中一些代码的解释,有兴趣的朋友可以看看。


本题有四个测试点,完成第一第二个可获得16分,剩下的是细节问题。

以下是0分代码,基本框架已经确定了,当时没写乘积的函数,因为和的函数都没弄懂。问题出现在使用attach函数时形参rear的传递,我用了指针rear作为形参传递,运行后总是显示出一个空格以及最后一个项的系数和指数。这个代码有多个错误,附上我当时的思考,希望帮助大家理解其中部分代码的作用。

#include<iostream>
using namespace std;
struct node
{
	int coef;
	int exp;
	struct node *next;
};
void attach(int c, int e, node *rear)//对形参rear的类型的定义是错误所在
{
	node *p = new node;
	p->coef = c;
	p->exp = e;
	p->next = NULL;
	rear->next = p;
	rear = p;//注意这一句的作用
}
node *read()//定义为node read()不可以,而改成这个定义方式就没有错误,为什么?因为我们的返回值是指针类型。
{
	int a, c, e;
	node *rear;//建立指向节点尾部的指针
	node *t;
	cin >> a;
	node *blank = new node;//建立空节点
	blank->next = NULL;
	rear = blank;//尾部指针指向空节点
	while (a--)
	{
		cin >> c >> e;
		attach(c, e, rear);
	}
	t = blank;//以下操作为删除空节点
	blank = blank->next;//空节点指针指向第一的节点,blank->next存放的是第一个节点的地址,本操作使blank成为指向第一个节点的指针
	delete t;
	return blank;
}
int compare(int a, int b)

{
	if (a > b)
		return 1;
	if (a < b)
		return 0;
	if (a == b)
		return -1;

}
node *add(node* p1, node *p2)
{
	node *front, *rear, *tt;
	front = new node;
	rear = front;
	int sum = 0;
	while (p1&&p2)
	{
		switch (compare(p1->exp, p2->exp))
		{
		case 1:
			attach(p1->coef, p1->exp, rear);
			p1 = p1->next;
			break;
		case 0:
			attach(p2->coef, p2->exp, rear);
			p2 = p2->next;
		case -1:
			sum = p1->coef + p2->coef;
			if (sum)attach(sum, p1->exp, rear);
			p1 = p1->next;
			p2 = p2->next;
			break;
		}
	}
	for (; p1 != 0; p1 = p1->next)
		attach(p1->coef, p1->exp, rear);
	for (; p2 != 0; p2 = p2->next)
		attach(p2->coef, p2->exp, rear);
	tt = front;
	front = front->next;
	delete tt;
	return front;
}
void print(node *p)
{
	if (!p)
	{
		cout << "0" << " " << 0 << endl;
	}
	int flag = 0;
	while (p)
	{
		if (!flag)
			flag = 1;
		else
			cout << " " << p->coef << " " << p->exp;
		p = p->next;
	}
	cout << endl;
}
int main()
{
	node *p1, *p2, *pp;
	p1 = read();
	p2 = read();
	pp = add(p1, p2);
	print(pp);
	return 0;
	system("pause");
}

如果试运行以上代码,结果只显示一个空格以及最后一个项的系数和指数,我觉得是指针类型的参数在被调函数内的修改依然无法返回到主调函数中,特别是我们的attach没有返回值,rear的每次修改都无法被记录,无法达到我们的目的。其实这个点mooc上有强调,我当时没能理解。后来查阅资料,了解到一个叫做指向指针的指针,能实现我们的目的。我们要求rear在被调函数中出来后,主调函数中的rear也同时被修改。我们就需要传递指针rear的地址,用指针的地址作为形参。其实只要是传递地址,就能实现这个目的。这应该是基本知识点了。

以下依然是0分代码。大问题出现在乘积函数mult里面。

#include<iostream>
using namespace std;
struct node
{
	int coef;
	int exp;
	struct node *next;
};

void attach(int c, int e, node **rear)
{
	node *p = new node;
	p->coef = c;
	p->exp = e;
	p->next = NULL;
	(*rear)->next = p;
	*rear = p;
}
node *read()/
{
	int a, c, e;
	node *rear;
	node *t;
	cin >> a;
	node *blank = new node;
	blank->next = NULL;
	rear = blank;
	while (a--)
	{
		cin >> c >> e;
		attach(c, e, &rear);
	}
	t = blank;
	blank = blank->next;
	delete t;
	return blank;
}
int compare(int a, int b)

{
	if (a > b)
		return 1;
	if (a < b)
		return 0;
	if (a == b)
		return -1;

}
node *add(node* p1, node *p2)
{
	node *front, *rear, *tt;
	front = new node;
	rear = front;
	int sum = 0;
	while (p1&&p2)
	{
		switch (compare(p1->exp, p2->exp))
		{
		case 1:
			attach(p1->coef, p1->exp, &rear);
			p1 = p1->next;
			break;
		case 0:
			attach(p2->coef, p2->exp, &rear);
			p2 = p2->next;
			break;
		case -1:
			sum = p1->coef + p2->coef;
			if (sum)
				attach(sum, p1->exp, &rear);
			p1 = p1->next;
			p2 = p2->next;
			break;
		}
	}
	for (; p1 != 0; p1 = p1->next)
		attach(p1->coef, p1->exp, &rear);
	for (; p2 != 0; p2 = p2->next)
		attach(p2->coef, p2->exp, &rear);
	tt = front;
	front = front->next;
	delete tt;
	return front;
}
void print(node *p)
{
	if (!p)
	{
		cout << "0" << " " <<" 0" << endl;
	}
	int flag = 0;
	while (p)
	{
		if (!flag)

			flag = 1;

		else
			cout << " ";


		cout << p->coef << " " << p->exp;
		p = p->next;
	}
	cout << endl;
}
node *mult(node* p1, node *p2)
{
	node *front, *rear, *tt;
	front = new node;
	front->next = NULL;
	rear = front;
	int c, e;
	if (!p1 || !p2)
		return NULL;
	
	while (p2)
	{
		c = p1->coef*p2->coef;
		e = p1->exp +p2->exp;
		attach(c, e, &rear);
		p2 = p2->next;
	}
	p1 = p1->next;
	while (p1)
	{
		rear = front;
		while (p2)//注意这个循环,我们结束这次循环之后,需要重新从p2的头部重新开始,而我们修改了p2的值,也没有是p2重新指向头部的操作,这是为什么用t2保存p2的原因。
		{
			c = p1->coef*p2->coef;
			e = p1->exp + p2->exp;
			while ((rear->next)&&(rear->next->exp > e))
				rear = rear->next;
			if ((rear->next)&&(rear->next->exp == e))
			{
				if ((rear->next->coef+c)!=0)
					rear->next->coef += c;
				else
				{
					tt = rear->next;
					rear->next = tt->next;
					delete tt;
				}
			}
			else
			{
				tt = new node;
				tt->coef = c;
				tt->exp = e;
				tt->next = rear->next;
				rear->next = tt;
				rear = rear->next;

			}

			p2 = p2->next;
		}
		p1 = p1->next;
	}
	tt = front;
	front = front->next;
	delete tt;
	return front;

}
int main()
{
	node *p1, *p2, *pp,*ps;
	p1 = read();
	p2 = read();
	pp = add(p1, p2);
	ps = mult(p1, p2);
	print(ps);
	print(pp);
	return 0;
	
}

我们对比满分代码,我们在mult中不是像上面这样直接对传递过来的p1,p2进行修改,而是将p1,p2分别保存在t1,t2中,相关操作对t1,t2进行。当时我在ppt中看到了,觉得多此一举,为什么不直接对p1,p2进行操作啊?答案如代码中的注释所示。

以下是18分代码。问题出现在和函数中,没办法通过第三个测试点。找到这个错误挺难的,不知道他的测试点是什么意思。还是要感谢csdn,有满分代码和前辈的解析,我从csdn看到一张测试表,找到了我的错误。

样例输入与输出:

序号输入输出
1
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
2
2 1 2 1 0
2 1 2 -1 0
1 4 -1 0
2 2
3
2 -1000 1000 1000 0
2 1000 1000 -1000 0
-1000000 2000 2000000 1000 -1000000 0
0 0
4
0
1 999 1000
0 0
999 1000

用以下代码,输入第三组数据,无法输出和多项式,并在vs2015上运行会出现错误(我无法看懂错误是什么,但我可以锁定错误在add函数中)


#include<iostream>
using namespace std;
struct node
{
	int coef;
	int exp;
	struct node *next;
};

void attach(int c, int e, node **rear)
{
	node *p = new node;
	p->coef = c;
	p->exp = e;
	p->next = NULL;
	(*rear)->next = p;
	*rear = p;//注意这一句的作用
}
node *read()//定义为node read()不可以,而改成这个定义方式就没有错误,为什么?
{
	int a, c, e;
	node *rear;//建立指向节点尾部的指针
	node *t;
	cin >> a;
	node *blank = new node;//建立空节点
	blank->next = NULL;
	rear = blank;//尾部指针指向空节点
	while (a--)
	{
		cin >> c >> e;
		attach(c, e, &rear);
	}
	t = blank;//以下操作为删除空节点
	blank = blank->next;//空节点指针指向第一的节点,blank->next存放的是第一个节点的地址,本操作使blank成为指向第一个节点的指针
	delete t;
	return blank;
}
int compare(int a, int b)

{
	if (a > b)
		return 1;
	if (a < b)
		return 0;
	if (a == b)
		return -1;

}
node *add(node* p1, node *p2)
{
	node *front, *rear, *tt;
	front = new node;
	
	rear = front;
	int sum = 0;
	while (p1&&p2)
	{
		switch (compare(p1->exp, p2->exp))
		{
		case 1:
			attach(p1->coef, p1->exp, &rear);
			p1 = p1->next;
			break;
		case 0:
			attach(p2->coef, p2->exp, &rear);
			p2 = p2->next;
			break;
		case -1:
			sum = p1->coef + p2->coef;
			if (sum)
				attach(sum, p1->exp, &rear);
			p1 = p1->next;
			p2 = p2->next;
			break;
		}
	}
	for (; p1 != 0; p1 = p1->next)
		attach(p1->coef, p1->exp, &rear);
	for (; p2 != 0; p2 = p2->next)
		attach(p2->coef, p2->exp, &rear);
	tt = front;
	front = front->next;
	delete tt;
	return front;
}
void print(node *p)
{
	if (!p)
	{
		cout << "0 0";//第四个测试点在这里!!格式要注意。
		cout << endl;
		return;
	}
	int flag = 0;
	while (p)
	{
		if (!flag)

			flag = 1;

		else
			cout << " ";


		cout << p->coef << " " << p->exp;
		p = p->next;
	}
	cout << endl;
}
node *mult(node* p1, node *p2)
{
	node *front, *rear, *tt, *t1, *t2;
	front = new node;
	front->next = NULL;
	rear = front;
	int c, e;
	if (!p1 || !p2)
		return NULL;
	t1 = p1; t2 = p2;
	while (t2)
	{
		c = t1->coef*t2->coef;
		e = t1->exp + t2->exp;
		attach(c, e, &rear);
		t2 = t2->next;
	}
	t1 = t1->next;
	while (t1)
	{
		t2 = p2;
		rear = front;
		while (t2)
		{
			c = t1->coef*t2->coef;
			e = t1->exp + t2->exp;
			while ((rear->next) && (rear->next->exp > e))
				rear = rear->next;
			if ((rear->next) && (rear->next->exp == e))
			{
				if ((rear->next->coef + c) != 0)
					rear->next->coef += c;
				else
				{
					tt = rear->next;
					rear->next = tt->next;
					delete tt;
				}
			}
			else
			{
				tt = new node;
				tt->coef = c;
				tt->exp = e;
				tt->next = rear->next;
				rear->next = tt;
				rear = rear->next;

			}

			t2 = t2->next;
		}
		t1 = t1->next;
	}
	tt = front;
	front = front->next;
	delete tt;
	return front;

}
int main()
{
	node *p1, *p2, *pp, *ps;
	p1 = read();
	p2 = read();
	pp = add(p1, p2);
	ps = mult(p2, p1);
	print(ps);
	print(pp);

	return 0;
}

我又试着输入诸如

1 -2 1

1 2 1

等,使和函数结果应为0 0的数据,但以上代码无法正常输出并且出现错误。 使用以上数据,相同指数的系数和为0,没建立节点,后面直接让front指向front->next,我以为机器会自动认为指向空,因为这种情况下front->next没有指向任何节点。后来发现它并不能自动指向空,那我们要在刚开始定义时就要令front->next指向空,这一句很有必要,定义时若没有用NULL初始化,front->next后来被赋值了还好,一旦没有被赋值,像以上所示的数据,就会出现错误,在add函数建立空节点front时加上

front->next=NULL;

就能满分了,如满分代码。


总之,寻找错误的过程是很烦的,但最终错误被修正还是很开心的。

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
算法与数据结构涵盖了以下主要内容: 数据结构(Data Structures): 逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并析这些操作的时间复杂度和空间复杂度。 算法: 算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,支限界法等。 算法析:通过数学方法析算法的时间复杂度(运时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法与数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值