實驗題目:多項式加法問題
實驗目的:設計一個一元稀疏多項式簡單計算器。實驗內容與要求 一元稀疏多項式簡單計算器的基本功能是: (1)輸入並建立多項式; (2)輸出多項式,輸出形式爲整數序列:n,c1,e1,c2,e2,…,cn,en,其中n是多項式的項數,ci和ei分別是第i項的係數和指數,序列按指數降序排列。 (3)多項式a與多項式b相乘,建立多項式。
實驗思路:
最樸素的想法就是用兩個數組來表示一個多項式,一個數組存放指數,另一個存放係數,下標相同代表同一項。當實現加法時,就需要尋找指數相同的項進行相加,把得到的結果存入另外一個數組當中去。當實現乘法是,我們就循環遍歷兩個式子,讓他們每個項之間兩兩相乘,結果保存在另外一個數組中。
然而注意到是一元稀疏多項式,也就是可能存在這樣的式子
那麼我們必須至少用長度爲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;
}
時間複雜度
指針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;
}
時間複雜度
第四步:進行相加
我們使用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;
}
時間複雜度
第五步:進行相乘
與加法類似,首先開闢一個新的鏈表用來保存相乘之後的結果。
但是我們需要用兩層循環,使得兩個多項式中的每一項兩兩相乘運算。
最後將結果保存。
實驗代碼
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;
}
時間複雜度
第六步:輸出
輸出就非常簡單了,重點是輸出的格式問題。我是將格式統一爲
直接看代碼吧
相加輸出代碼
while (p3!=NULL)
{
printf("%.2f * x^%d", p3->coef, p3->expon);
p3 = p3->link;
if (p3 != NULL && p3->coef > 0)
printf("+");
}
時間複雜度
相乘輸出代碼
爲了將次數一樣的項合併,乘法的輸出稍微複雜一點
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);
}
時間複雜度
時間複雜度分析
假設多項式一的項數是,多項式二的項數是。由於我的程序各個部分的函數都是獨立的,沒有什麼嵌套的關係,因此時間複雜度就是各部分時間複雜度最大的那個。在本程序裏,時間複雜度最高的就是排序和相乘的,然而當輸入是按照從高到低的次數進行輸入的時候,排序的時間複雜度就可以降到
相乘的每兩項相乘是不可避免的,因此本實驗的時間複雜度爲
運行截圖
測試1:
多項式1:
多項式2:
結果:
相加
相乘
測試結果:
測試2:
多項式1:
多項式2:
結果:
相加
相乘
測試結果:
測試3:
多項式1:
多項式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);
}
}