PTA 一元多项式的乘法与加法运算 思路分析及代码解析 v0.93

一、前导

1. 需要掌握的知识

  1. 链表
  2. 一元多项式

2. 题目信息

  1. 题目来源:PTA / 拼题A
  2. 题目地址: 一元多项式的乘法与加法运算

二、解题思路分析

1. 题意理解

  1. 输入数据
4 3 4 -5 2  6 1  -2 0  //第一个一元多项式:首数字4表示多项式非零项的个数,随后以指数递降的方式,输入多项式非零项系数和指数
3 5 20  -7 4  3 1	//第二个一元多项式
  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 //两个多项式加法运算的结果
  1. 题意
    编程进行一元多项式的乘法和加法运算并打印结果

2. 思路分析(重点)

本题锻炼链表的基本使用:创建和插入,插入函数是AC的重点

三、具体实现

1. 弯路和bug

  1. 通过链表存储数据和操作数据时,需要更细致一些,避免指向错误的位置

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 各分支函数

  1. 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;
	
}
  1. 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;
}
  1. 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;
}
  1. Add( ) 多项式加法运算:后面没有其他运算了,直接在已有的多项式数据上执行插入
PtrPoly Add(PtrPoly a, PtrPoly b)
{	
	b=b->next;
	while(b)
	{
		a=Insert(a,b);
		b=b->next;
	}	
	return a;
}
  1. 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;
}

四、参考资料

浙江大学 陈越、何钦铭老师主讲的数据结构

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值