数据结构第一次实验

实验题目:多项式加法问题
实验目的:设计一个一元稀疏多项式简单计算器。实验内容与要求 一元稀疏多项式简单计算器的基本功能是: (1)输入并建立多项式; (2)输出多项式,输出形式为整数序列:n,c1,e1,c2,e2,…,cn,en,其中n是多项式的项数,ci和ei分别是第i项的系数和指数,序列按指数降序排列。 (3)多项式a与多项式b相乘,建立多项式。

实验思路:

最朴素的想法就是用两个数组来表示一个多项式,一个数组存放指数,另一个存放系数,下标相同代表同一项。当实现加法时,就需要寻找指数相同的项进行相加,把得到的结果存入另外一个数组当中去。当实现乘法是,我们就循环遍历两个式子,让他们每个项之间两两相乘,结果保存在另外一个数组中。

然而注意到是一元稀疏多项式,也就是可能存在这样的式子
f ( x ) = 10 x 1000 + 6 x 2 f(x) = 10x^{1000}+6x^{2} f(x)=10x1000+6x2
那么我们必须至少用长度为1000的数组来存储,并且其中大多数数组的元素为零。这样算法的空间复杂度很高也很浪费。

因此决定使用链表这一数据结构来表示。

默认多项式一的长度为n,多项式二的长度为m。

实验步骤:

第一步:建立存储的链表

第一步我们需要定义一个链表,里面保存每一项的系数和指数。并且分别定义两个这样的链表,来表示需要相加的两个多项式。

实验代码

struct  PolyNode
{
	float coef; // 指数,考虑小数的情况
	int expon; // 次数
	struct PolyNode *link; // 后继节点
};
typedef struct PolyNode *Polynomial;
Polynomial p1, p2; //代表输入的两个多项式

第二步:明确读入数据并保存

我们的思路是,对于每个需要读入的多项式,首先读入项数。接着,按照指数的高低,分别读入。

专门写了一个ReadPoly()函数用来读取多项式

实验代码

Polynomial ReadPoly(int n1)
{
	Polynomial P, rear, t;
	P = (Polynomial)malloc(sizeof(struct PolyNode));
	P->link = NULL;
	rear = P;
	for (int i = 1; i <= n1; i++)
	{
		float c; int f;
		printf("第%d项系数:", i); // 输入第i项系数
		scanf("%f", &c);
		printf("第%d项次数:", i); // 输入第i项次数
		scanf("%d", &f);
		Attach(c, f, &rear); // 链接成链表
	}
	t = P; P = P->link;
	free(t);
	return P;
}

时间复杂度
O ( N + M ) O(N+M) O(N+M)

指针P 用来保存多项式的结果。如何将输入的每一组系数和指数联系起来,我们则需要用一个Attach函数去完成。

第三步:将读入的系数和指数连接起来

写一个Attach 函数,新开辟一个节点,将指数和系数保存到节点当中,再将节点连接到rear链表的后面。

实验代码

void Attach(int c, int e, Polynomial *pRear)
{
	Polynomial p;
	p = (Polynomial)malloc(sizeof(struct PolyNode)); // 开辟新节点
	p->coef = c;  // 系数
	p->expon = e; // 次数
	p->link = NULL;
	(*pRear)->link = p;
	*pRear = p;
}

第四步:进行排序

我们默认输入是随机的,可以不按照次数降序排列。因此需要一个排序的函数进行排序。

实验代码

Polynomial Sort(Polynomial pHead)//链表排序
{
	Polynomial P = pHead;
	Polynomial p = NULL;
	Polynomial q = NULL;
	int temp;
	float tmp2;
	// 冒泡排序
	for (p= pHead; p != NULL; p = p->link)
	{
		for (q = p->link; q != NULL; q = q->link)
		{
			if (p->expon < q->expon)
			{
				// 分别交换系数和次数
				temp = p->expon; 
				tmp2 = p->coef;
				p->expon = q->expon;
				p->coef = q->coef;
				q->expon = temp;
				q->coef = tmp2;
			}
		}
	}
	return pHead;
}

时间复杂度
O ( N M ) O(NM) O(NM)

第四步:进行相加

我们使用PolyAdd() 函数进行相加。逻辑如下:

首先开辟一个新的链表用来保存相加之后的结果。
比较两个多项式的每一项,如果相同就进行系数相加并且存入新的链表。如果第一个的指数大,那么第二个就向后移动一个;如果第一个的指数小,那么第一个就向后移动一个。

只要当p1和p2任何一个为空时,那么比较就结束,p1或p2剩余没有比较的部分就自动存到p3后面。

其中,Compare函数是用来比较次数的大小,如果相同,返回0;如果前者大返回1,后者大返回-1.
实验代码

Polynomial PolyAdd(Polynomial p1, Polynomial p2)
{
	Polynomial Front, rear, temp;
	float sum;
	rear = (Polynomial)malloc(sizeof(struct PolyNode));
	Front = rear;
	while (p1&&p2) // 比较条件,都不为空
	{
		switch (Compare(p1->expon, p2->expon)) { // Compare 来比较大小
		case 1:
			Attach(p1->coef, p1->expon, &rear);
			p1 = p1->link; // 前者比较大的情况
			break;
		case -1:
			Attach(p2->coef, p2->expon, &rear);
			p2 = p2->link; // 后者比较大的情况
			break;
		case 0:
			sum = p1->coef + p2->coef;
			if (sum) Attach(sum, p1->expon, &rear); // 相加
			p1 = p1->link;
			p2 = p2->link;
			break;
		}
	}
	for (; p1; p1 = p1->link) Attach(p1->coef, p1->expon, &rear); // 保存剩余项
	for (; p2; p2 = p2->link) Attach(p2->coef, p2->expon, &rear); // 保存剩余项
	rear->link = NULL; // 最后为空
	temp = Front;
	Front = Front->link;
	free(temp);
	return Front;
}

时间复杂度
O ( m a x ( N , M ) ) O(max(N,M)) O(max(N,M))

第五步:进行相乘

与加法类似,首先开辟一个新的链表用来保存相乘之后的结果。

但是我们需要用两层循环,使得两个多项式中的每一项两两相乘运算。

最后将结果保存。

实验代码

Polynomial PolyMulti(Polynomial p1, Polynomial p2)
{
	Polynomial front, rear, temp;
	front = rear = (Polynomial)malloc(sizeof(struct PolyNode));
	Polynomial t1, t2;
	float product_coef; int product_expon;
	if (!p1 || !p2) return NULL;
	// 令每一项相乘
	for (t1 = p2; t1; t1 = t1->link)
	{
		for (t2 = p1; t2; t2 = t2->link)
		{
			product_coef = (t1->coef)*(t2->coef);
			product_expon = (t1->expon) + (t2->expon);
			Attach(product_coef, product_expon, &rear);
		}
	}
	temp = front;
	front = front->link;
	free(temp);
	return front;
}

时间复杂度
O ( N M ) O(NM) O(NM)

第六步:输出

输出就非常简单了,重点是输出的格式问题。我是将格式统一为
c o e f e x p o n coef \quad expon coefexpon
直接看代码吧

相加输出代码

while (p3!=NULL)
{
	printf("%.2f * x^%d", p3->coef, p3->expon);
	p3 = p3->link;
	if (p3 != NULL && p3->coef > 0)
		printf("+");
}

时间复杂度
O ( N + M ) O(N+M) O(N+M)
相乘输出代码

为了将次数一样的项合并,乘法的输出稍微复杂一点

    float C = p4->coef;
	int E = p4->expon;
	p4 = p4->link;
	if(p4==NULL)
		printf("%.2f*x^%d ", C, E);
	while (p4 != NULL)
	{
		int flag = 0;
		while (p4->expon == E && p4!=NULL)
		{
			C += p4->coef;
			if(p4->link!=NULL)
				p4 = p4->link;
			flag++;
		}
		printf("%.2f * x^%d ", C,E);
		C = p4->coef;
		E = p4->expon;
		p4 = p4->link;
		if (p4 != NULL && p4->coef > 0)
			printf("+");
		if(!p4)
			if (C>0)
				printf("+ %.2f * x^%d ", C, E);
			else
				printf("%.2f * x^%d ", C, E);
	}

时间复杂度

O ( N M ) O(NM) O(NM)

时间复杂度分析

假设多项式一的项数是 n n n,多项式二的项数是 m m m。由于我的程序各个部分的函数都是独立的,没有什么嵌套的关系,因此时间复杂度就是各部分时间复杂度最大的那个。在本程序里,时间复杂度最高的就是排序和相乘的 O ( N M ) O(NM) O(NM),然而当输入是按照从高到低的次数进行输入的时候,排序的时间复杂度就可以降到 ( N ) (N) (N)

相乘的每两项相乘是不可避免的,因此本实验的时间复杂度为

O ( N M ) O(NM) O(NM)

运行截图

测试1:

多项式1:

f ( x ) = x 6 + 2 x 3 − 7 x 2 + 2 f(x) = x^6+2x^3-7x^2+2 f(x)=x6+2x37x2+2

多项式2:

f ( x ) = 3 x 4 − 4 x 3 + 2 x − 7 f(x) = 3x^4-4x^3+2x-7 f(x)=3x44x3+2x7

结果:
相加

f ( x ) = x 6 + 3 x 4 − 2 x 3 − 7 x 2 + 2 x − 5 f(x) = x^6+3x^4-2x^3-7x^2+2x-5 f(x)=x6+3x42x37x2+2x5
相乘

f ( x ) = 3 x 10 − 4 9 + 8 x 7 − 36 x 6 + 28 x 5 + 10 x 4 − 36 x 3 + 49 x 2 + 4 x − 14 f(x) = 3x^{10}-4^9+8x^7-36x^6+28x^5+10x^4-36x^3+49x^2+4x-14 f(x)=3x1049+8x736x6+28x5+10x436x3+49x2+4x14

测试结果:
在这里插入图片描述

测试2:

多项式1:
f ( x ) = 20 x 1000 − 7 f(x) = 20x^{1000}-7 f(x)=20x10007
多项式2:
f ( x ) = x 2 + 1 f(x) = x^2+1 f(x)=x2+1
结果:
相加
f ( x ) = 2 0 1000 + x 2 − 6 f(x) = 20^{1000}+x^2-6 f(x)=201000+x26
相乘
f ( x ) = 2 0 1002 + 2 0 1000 − 7 x 2 − 7 f(x) = 20^{1002}+20^{1000} -7x^2-7 f(x)=201002+2010007x27

测试结果:
在这里插入图片描述
测试3:

多项式1:
f ( x ) = 0.2 x 2 + 0.1 x 1 f(x) = 0.2x^{2}+0.1x^1 f(x)=0.2x2+0.1x1
多项式2:
f ( x ) = 0.4 x 2 + 0.6 x 1 f(x) = 0.4x^2+0.6x^1 f(x)=0.4x2+0.6x1
结果:
相加
f ( x ) = 0.6 x 2 + 0.7 x 1 f(x) = 0.6x^{2}+0.7x^1 f(x)=0.6x2+0.7x1
相乘
f ( x ) = 0.08 x 4 + 0.16 x 3 + 0.06 x 2 f(x) = 0.08x^4+0.16x^3+0.06x^2 f(x)=0.08x4+0.16x3+0.06x2

测试结果:
在这里插入图片描述

心得体会

本次实验完成了稀疏多项式的乘法和加法,主要用了链表的操作和运算。在本次实验中,我学会了如何分析时间复杂度,让程序的运行效率更好;还学会了如何链表这一数据结构内在的层次逻辑,如何链接链表等等。对于链表而言,判断是否为空是非常重要的,如果没有判断链表为空会出现一定的错误,或者程序报错。

附录:完整代码

#include <stdio.h>
#include <stdlib.h>

struct  PolyNode
{
	float coef;
	int expon;
	struct PolyNode *link;
};
typedef struct PolyNode *Polynomial;
Polynomial p1, p2;
int num = 0;
void Attach(float c, int e, Polynomial *pRear)
{
	Polynomial p;
	p = (Polynomial)malloc(sizeof(struct PolyNode));
	p->coef = c;
	p->expon = e;
	p->link = NULL;
	(*pRear)->link = p;
	*pRear = p;
}
int Compare(int c1, int c2)
{
	if (c1 == c2)
		return 0;
	if (c1 > c2)
		return 1;
	else
		return -1;
}
Polynomial PolyAdd(Polynomial p1, Polynomial p2)
{
	Polynomial Front, rear, temp;
	float sum;
	rear = (Polynomial)malloc(sizeof(struct PolyNode));
	Front = rear;
	while (p1&&p2)
	{
		switch (Compare(p1->expon, p2->expon)) {
		case 1:
			Attach(p1->coef, p1->expon, &rear);
			p1 = p1->link;
			break;
		case -1:
			Attach(p2->coef, p2->expon, &rear);
			p2 = p2->link;
			break;
		case 0:
			sum = p1->coef + p2->coef;
			if (sum) Attach(sum, p1->expon, &rear);
			p1 = p1->link;
			p2 = p2->link;
			break;
		}
	}
	for (; p1; p1 = p1->link) { Attach(p1->coef, p1->expon, &rear); }
	for (; p2; p2 = p2->link) { Attach(p2->coef, p2->expon, &rear); }
	rear->link = NULL;
	temp = Front;
	Front = Front->link;
	free(temp);
	return Front;
}
Polynomial PolyMulti(Polynomial p1, Polynomial p2)
{
	Polynomial front, rear, temp;
	front = rear = (Polynomial)malloc(sizeof(struct PolyNode));
	Polynomial t1, t2;
	float product_coef;
	int product_expon;
	if (!p1 || !p2) return NULL;
	for (t1 = p2; t1; t1 = t1->link)
	{
		for (t2 = p1; t2; t2 = t2->link)
		{
			product_coef = (t1->coef)*(t2->coef);
			product_expon = (t1->expon) + (t2->expon);
			Attach(product_coef, product_expon, &rear);
		}
	}
	temp = front;
	front = front->link;
	free(temp);
	return front;
}
Polynomial ReadPoly(int n1)
{
	Polynomial P, rear, t;
	P = (Polynomial)malloc(sizeof(struct PolyNode));
	P->link = NULL;
	rear = P;
	for (int i = 1; i <= n1; i++)
	{
		float c; int f;
		printf("第%d项系数:", i);
		scanf("%f", &c);
		printf("第%d项次数:", i);
		scanf("%d", &f);
		Attach(c, f, &rear);
	}
	t = P; P = P->link;
	free(t);
	return P;
}


Polynomial Sort(Polynomial pHead)//链表排序
{
	Polynomial P = pHead;
	Polynomial p = NULL;
	Polynomial q = NULL;
	int temp;
	float tmp2;
	for (p= pHead; p != NULL; p = p->link)
	{
		for (q = p->link; q != NULL; q = q->link)
		{
			if (p->expon < q->expon)
			{
				temp = p->expon;
				tmp2 = p->coef;
				p->expon = q->expon;
				p->coef = q->coef;
				q->expon = temp;
				q->coef = tmp2;
			}
		}
	}
	return pHead;
}

int main()
{
	int n1, n2;
	Polynomial p5 = NULL;
	Polynomial p6 = NULL;
	Polynomial p7 = NULL;
	printf("请输入多项式1的项数:\n");
	scanf("%d", &n1);
	printf("请分别输入多项式1的系数和次数:\n");
	p1=ReadPoly(n1);
	p1 = Sort(p1);
	p5 = p1;
	printf("请输入多项式2的项数:\n");
	scanf("%d", &n2);
	printf("请分别输入多项式2的系数和次数:\n");
	p2=ReadPoly(n2);
	p2 = Sort(p2);
	p6 = p2;
	Polynomial p3 = NULL;
	Polynomial p4 = NULL;
	p3 = PolyAdd(p1, p2);
	p7= PolyMulti(p5, p6);
	p4 = Sort(p7);
	while (p3!=NULL)
	{
		num++;
		p3 = p3->link;
	}
	p3 = PolyAdd(p1, p2);
	printf("\n相加之后的多项式项数为:%d \n", num);
	printf("\n相加之后的多项式为:\n");
	while (p3!=NULL)
	{
		printf("%.2f %d ", p3->coef, p3->expon);
		p3 = p3->link;
	}
	printf("\n相乘之后的多项式:\n");
	float C = p4->coef;
	int E = p4->expon;
	p4 = p4->link;
	if(p4==NULL)
		printf("%.2f %d ", C, E);
	while (p4 != NULL)
	{
		int flag = 0;
		while (p4->expon == E && p4!=NULL)
		{
			C += p4->coef;
			if(p4->link!=NULL)
				p4 = p4->link;
			flag++;
		}
		printf("%.2f %d ", C,E);
		C = p4->coef;
		E = p4->expon;
		p4 = p4->link;
		if(!p4)
			printf("%.2f %d ", C, E);
	}
}
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值