數據結構第一次實驗

實驗題目:多項式加法問題
實驗目的:設計一個一元稀疏多項式簡單計算器。實驗內容與要求 一元稀疏多項式簡單計算器的基本功能是: (1)輸入並建立多項式; (2)輸出多項式,輸出形式爲整數序列:n,c1,e1,c2,e2,…,cn,en,其中n是多項式的項數,ci和ei分別是第i項的係數和指數,序列按指數降序排列。 (3)多項式a與多項式b相乘,建立多項式。

實驗思路:

最樸素的想法就是用兩個數組來表示一個多項式,一個數組存放指數,另一個存放係數,下標相同代表同一項。當實現加法時,就需要尋找指數相同的項進行相加,把得到的結果存入另外一個數組當中去。當實現乘法是,我們就循環遍歷兩個式子,讓他們每個項之間兩兩相乘,結果保存在另外一個數組中。

然而注意到是一元稀疏多項式,也就是可能存在這樣的式子
f(x)=10x1000+6x2f(x) = 10x^{1000}+6x^{2}
那麼我們必須至少用長度爲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)

指針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(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(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(NM)O(NM)

第六步:輸出

輸出就非常簡單了,重點是輸出的格式問題。我是將格式統一爲
coefexponcoef \quad expon
直接看代碼吧

相加輸出代碼

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)
相乘輸出代碼

爲了將次數一樣的項合併,乘法的輸出稍微複雜一點

    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(NM)O(NM)

時間複雜度分析

假設多項式一的項數是nn,多項式二的項數是mm。由於我的程序各個部分的函數都是獨立的,沒有什麼嵌套的關係,因此時間複雜度就是各部分時間複雜度最大的那個。在本程序裏,時間複雜度最高的就是排序和相乘的O(NM)O(NM),然而當輸入是按照從高到低的次數進行輸入的時候,排序的時間複雜度就可以降到(N)(N)

相乘的每兩項相乘是不可避免的,因此本實驗的時間複雜度爲

O(NM)O(NM)

運行截圖

測試1:

多項式1:

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

多項式2:

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

結果:
相加

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

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

測試結果:
在這裏插入圖片描述

測試2:

多項式1:
f(x)=20x10007f(x) = 20x^{1000}-7
多項式2:
f(x)=x2+1f(x) = x^2+1
結果:
相加
f(x)=201000+x26f(x) = 20^{1000}+x^2-6
相乘
f(x)=201002+2010007x27f(x) = 20^{1002}+20^{1000} -7x^2-7

測試結果:
在這裏插入圖片描述
測試3:

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

測試結果:
在這裏插入圖片描述

心得體會

本次實驗完成了稀疏多項式的乘法和加法,主要用了鏈表的操作和運算。在本次實驗中,我學會了如何分析時間複雜度,讓程序的運行效率更好;還學會了如何鏈表這一數據結構內在的層次邏輯,如何鏈接鏈表等等。對於鏈表而言,判斷是否爲空是非常重要的,如果沒有判斷鏈表爲空會出現一定的錯誤,或者程序報錯。

附錄:完整代碼

#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);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章