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

本文介绍了两种实现一元稀疏多项式乘法的方法:链表和顺序表。链表方法虽然直观,但时间复杂度较高;顺序表利用map实现了高效合并,避免了额外排序。实验结果显示,两种方法都能正确处理各种情况,输出正确答案,但顺序表在处理大量数据时可能更优。
摘要由CSDN通过智能技术生成

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永远滴神
实验一 线性表及其应用 一、 实验目的和要求 1、掌握线性表的插入、删除、查找等基本操作设计与实现 2、学习利用线性表提供的接口去求解实际问题 3、熟悉线性表的的存储方法 二、 实验内容和原理 1、实验内容:设计一个一元多项式的简单计算器,其基本功能有①输入并建立多项式;②输出多项式;③多项式相加。可利用单链表或单循环链表实现之。 2、实验原理:以线性表来描述一元多项式,存储结构采用单链表,每个结点存储的多项式中某一项的系数和指数,建立单链表时指数高的结点列于指数低的 结点之后,即线性表的元素按指数递增有序排列。 三、 实验环境 Visual C++ 6.0 及PC机 四、 算法描述及实验步骤 思想算法: 以线性表来描述一元多项式,存储结构采用单链表,每个结点存储的多项式中某一项的系数和指数,建立单链表时指数高的结点列于指数低的结点之后,即线性表的元素按指数递增有序排列。 例如构造两个多项式ha: 5X3+4X2+3X+2 hb: X2+X+1 多项式加法:定义指针p,q分别指向ha,hb i.p->exp==q->exp ,r->coef=p->coef+q->coef,pa,pb下移; ii.p->expexp ,r->coef=q->coef;r->exp=q->exp;,q下移 iii.pa->exp>pb->exp, r->exp=p->exp;r->coef=p->coef;,p下移 iv.p!=NULL,pb==NULL.相当于iii. V.q==NULL,pb!=NULL.相当于ii. 其流程图如下: 多项式乘法:定义指针fp,gp分别指向f,g 1.将两多项式最大指数相加并赋于maxp,并置g 2.用for循环求指数等于maxp时相乘的系数 3. (fp!=NULL)&&(gp!=NULL), p=fp->exp+gp->exp 1.p>maxp, fp=fp->next; 2. pnext; 3.p=maxp, x+=fp->coef*gp->coef; fp=fp->next;gp=gp->next; 五、 实验结果 1.分别输入两个多项式: 5X3+4X2+3X+2 和X2+X+1,然后输出结果如下: 2.分别输入两个多项式:6X4+4X2+2和5X+6,然后输出结果如下: 六、 总结 此次上机实验应用了线性表实现了一次实际操作,完成了一个一元多项式的简单计算器,不仅对此次编译程序的算法思想有了新的认识,还让我深刻的体到了线性表的重要性以及其应用的方便,并且对指针加深了映象,应用了书本中的算法思想,对我以后的编译以及完成新的程序有很大的帮助。 附录: 1.建立多项式列表代码如下: mulpoly *creatpoly()/*建立多项式列表*/ {mulpoly *head,*r,*s;/*设中间变量*/ int m,n; head=(mulpoly *)malloc(sizeof(mulpoly));/*头结点申请空间*/ printf("\ninput coef and exp:\n"); scanf("%d%d",&n,&m);/*输入多项式系数和指数*/ r=head;/*尾指针指向头指针*/ while(n!=0)/*将输入的多项式存放在S中*/ {s=(mulpoly*)malloc(sizeof(mulpoly)); s->coef=n; s->exp=m; r->next=s; r=s; /*printf("input coef and exp:\n");*/ scanf("%d%d",&n,&m);/*再次输入多项式系数和指数*/ } r->next=NULL;/*将尾指针置空*/ head=head->next;/*将head哑结点向前跑一个结点,使其不为空*/ return (head);/*返回多项式*/ } 2.两个多项式相加代码如下: mulpoly *polyadd(mulpoly *ha,mulpoly *hb)/*两个多项式相加*/ {mulpoly *hc,*p,*q,*s,*r;/*声明结构体型*/ int x; p=ha; q=hb; hc=(mulpoly *)malloc(sizeof(mulpoly));/*申请结点空间*/ s=hc; while((p!=NULL)&&(q!=NULL))/*两多项式不为空*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值