数据结构实验一:多项式乘法问题

Exp01 多项式乘法问题

Author: Maskros

实验目的

设计一个一元稀疏多项式简单计算器

实验内容与要求

一元稀疏多项式简单计算器的基本功能是:

(1)输入并建立多项式。

(2)输出多项式,输出形式为整数序列: n , c 1 , e 1 , c 2 , e 2 , . . . , c n , e n n,c_1,e_1,c_2,e_2,...,c_n,e_n n,c1,e1,c2,e2,...,cn,en, 其中 n n n 是多项式的项数, c i c_i ci e i e_i ei 分别是第 i i i 项的系数和指数,序列按指数 降序排列。

(3)多项式 a a a 与多项式 b b b 相乘,建立多项式。

实验内容和实验步骤

在这里我们分别通过顺序表和链表两种方法来实现实验要求

  • 大体思路:
    • 链表 O ( N 2 ) O(N^2) O(N2)
      • 结构体Pol存储多项式每项的系数和指数
      • CreatePol(Pol *&head)函数用于接收输入的多项式元素,创建一个多项式
      • PrintPol(Pol *&head)函数用于打印多项式
      • MultiPol(Pol *&a, Pol *&b, Pol *&c)函数用于实现多项式的乘法,每次插入一项顺序遍历新链表 ,按指数升序插入或合并,最后得到以 *c为头结点的链表,即所求结果
      • Getlength(Pol &pol)函数遍历链表返回多项式的项数,用于打印时使用
      • ps:计算出来是空项的判断依据为 pol->c=0 , 故在输出和计算长度时将其直接忽略
    • 顺序表 O ( ( l o g N ) 2 ) O((logN)^2) O((logN)2)
      • 使用定义的map类型 typedef map<int, int> Pol存储多项式每项的系数和指数, key为指数,value为系数,map.size()为多项式项数
      • create()函数用于接收输入的多项式元素,创建一个多项式
      • print(Pol &pol)函数用于打印多项式
      • multi(Pol &p1, Pol &p2)函数用于实现多项式的乘法,完成合并后,返回一个Pol类型的多项式
      • 使用map的好处:由于map遍历的特性,不用再次从小到大排序,并且易于查找和合并同类项
  • 输入形式:两个多项式,两个整数序列 n , c 1 , e 1 , c 2 , e 2 , . . . , c n , e n n,c_1,e_1,c_2,e_2,...,c_n,e_n n,c1,e1,c2,e2,...,cn,en, 其中 n n n 是多项式的项数, c i c_i ci e i e_i ei 分别是第 i i i 项的系数和指数,序列按指数 降序排列
  • 输出形式:一个整数序列 n , c 1 , e 1 , c 2 , e 2 , . . . , c n , e n n,c_1,e_1,c_2,e_2,...,c_n,e_n n,c1,e1,c2,e2,...,cn,en,标号规则同上

链表实现

//presented by Maskros - 2021/03/31
#include<bits/stdc++.h>
using namespace std;
struct Pol{
	int c;	//coefficient
	int e;	//exponent
	Pol *next;
};
int Getlength(Pol *&head){	//Calculate the number of terms in a polynomial
	if(head==NULL) {cout<<"NO_ELEM_ERROR"<<endl; return 0;}
	Pol *p=head;
	int cnt=0;
	while(p->next!=NULL){
		p=p->next;
		if(p->c==0) cnt--;	//Empty items are not included in the count
		cnt++;
	}
	return cnt;
}

void CreatePol(Pol *&head){	//Create a polynomial
	//initialization
	head=(Pol *) new Pol;
	head->c=0;
	head->e=0;
	head->next=NULL;

	Pol *pol=head;
	int n; cin>>n;
	for(int i=1;i<=n;i++){
		pol->next=(Pol *) new Pol;  
		pol=pol->next;
		cin>>pol->c>>pol->e;
		pol->next=NULL;
	}
	return;
}
void PrintPol(Pol *&head){	//Print polynomial	
	Pol *p=head;
	int n=Getlength(p);
	cout<<n<<" ";
	while(p->next!=NULL){
		p=p->next;
		if(p->c!=0) cout<<p->c<<" "<<p->e<<" ";  //Do not print empty items
	}
	return;
}
void MultiPol(Pol *&a, Pol *&b, Pol *&c){	//Polynomial multiplication
	Pol *p1=a, *p2=b;
	int tmpc,tmpe;
	bool t;		//Check if the item has been inserted
	c=(Pol *) new Pol;
	c->c=0; c->e=0; c->next=NULL;	//initialization
	Pol *p3,*pre;	//$pre$ is the node before the current position
	while(p1->next!=NULL){
		p1=p1->next;
		p2=b;
		while(p2->next!=NULL){
			p2=p2->next;
			t=false;
			tmpc=p1->c*p2->c;
			tmpe=p1->e+p2->e;
			p3=c;
			pre=c;
			while(p3->next!=NULL){	
				p3=p3->next;
				if(p3->e>tmpe){		//The insertion position is before the current position
					pre->next=(Pol *)new Pol;
					pre=pre->next;
					pre->e=tmpe;
					pre->c=tmpc;
					pre->next=p3;
					t=true;
				}
				else if(p3->e==tmpe){	//Combine similar items at current location
					p3->c+=tmpc;
					t=true;
				}
				else if(p3->next!=NULL && p3->e<tmpe && p3->next->e>tmpe){	//The insertion position is after the current position
					pre=p3->next;
					p3->next=(Pol *)new Pol;
					p3=p3->next;
					p3->e=tmpe;
					p3->c=tmpc;
					p3->next=pre;
					t=true;
				}
				if(t==true) break;
				pre=p3;
			}
			if(t==false){	//Insertion position is at the end of the linked list
				p3->next=(Pol *)new Pol;
				p3=p3->next;
				p3->e=tmpe;
				p3->c=tmpc;
				p3->next=NULL;
			}
		}
	}
	return ;
}
int main(){
	Pol *p1,*p2,*p3;
	p1=NULL,p2=NULL,p3=NULL;
	CreatePol(p1);
	CreatePol(p2);
	MultiPol(p1,p2,p3);
	PrintPol(p3);
	return 0;
}

顺序表实现

//presented by Maskros - 2021/03/31
#include<bits/stdc++.h>
using namespace std;
typedef map<int, int> Pol; 
Pol p1,p2,p3;
void create(Pol &pol){	//Create a polynomial
	int co,ex,n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>co>>ex;
		pol[ex]+=co; 
	}
}
void print(Pol &pol){	//Print polynomial
	map<int,int>::iterator it;
	cout<<pol.size()<<" ";
	for(it=pol.begin();it!=pol.end();it++){
		cout<<it->second<<" "<<it->first<<" ";  
	}
}
Pol multi(Pol &p1, Pol &p2){	//Polynomial multiplication
	Pol p3;
	map<int,int>::iterator it1,it2;
	for(it1=p1.begin();it1!=p1.end();it1++){
		for(it2=p2.begin();it2!=p2.end();it2++){
			p3[it1->first+it2->first]+=it1->second*it2->second;		//Insert p3 after multiplying directly
			if(p3[it1->first+it2->first]==0) p3.erase(it1->first+it2->first);	//Delete extra items
		}
	}
	return p3;
}
int main(){
	create(p1);
	create(p2);
	p3=multi(p1,p2);
	print(p3);
	return 0;
}

实验用测试数据和相关结果分析

INPUT1:
2 1 2 3 4
3 1 3 1 5 2 6
OUTPUT1:
5 1 5 4 7 2 8 3 9 6 10

INPUT2:
3 2 0 3 2 4 3
3 -1 0 1 1 4 3
OUTPUT2:
7 -2 0 2 1 -3 2 7 3 4 4 12 5 16 6

IUPUT3:
3 -1 -1 1 0 1 1
2 2 -2 3 2 
OUTPUT3:
6 -2 -3 2 -2 2 -1 -3 1 3 2 3 3

INPUT4:
2 1 0 1 1
2 -1 0 1 1
OUTPUT4:
2 -1 0 1 2
  • 结果分析:由此可见,无论是错序合并,系数、项数取正、负、零,以及结果出现零项的处理均可实现,输出正确答案

实验总结

  • 链表写起来比较基础,对于插入、遍历、删除等操作无法取巧,包括在计算多项式的长度时都需要遍历,只能扎扎实实来写,排序的工作在插入的时候直接就按照顺序插入来完成,如果数据量比较大的话感觉时间复杂度有点高,所以有点小麻烦,但是感觉写下来一趟,强化了我对于指针、地址、空间等方面的理解,写起来也没有之前那么生疏了
  • 顺序表一开始打算用 struct 型的 vector 来存,然后直接插入,最后再sort()一下方便排序,结果在相同项合并的操作上发现还是需要像链表一样遍历去查找位置,所以感觉有点麻烦,本来写好了就全删了,换了一种思路,用 map 来实现
    式的长度时都需要遍历,只能扎扎实实来写,排序的工作在插入的时候直接就按照顺序插入来完成,如果数据量比较大的话感觉时间复杂度有点高,所以有点小麻烦,但是感觉写下来一趟,强化了我对于指针、地址、空间等方面的理解,写起来也没有之前那么生疏了
  • 顺序表一开始打算用 struct 型的 vector 来存,然后直接插入,最后再sort()一下方便排序,结果在相同项合并的操作上发现还是需要像链表一样遍历去查找位置,所以感觉有点麻烦,本来写好了就全删了,换了一种思路,用 map 来实现
  • 用 map 太爽了,30来行就完事了,不用手动排序,查找合并也很方便,除了加了一个空项的erase()删除工作,基本上没什么坑,遍历也很舒服,stl永远滴神
  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值