實驗報告格式規范,包括以下內容:(正文 宋體五號 )
一、問題描述(標題黑體小四)
對簡單的一元多項式相加、相減、求導運算。
二、實驗目的
實現對簡單的一元多項式相加、相減、求導運算。
三、實驗設計
1.邏輯結構
邏輯結構是指數據元素之間的邏輯關系,即從邏輯關系上描述數據。它與數據的存儲無關,是獨立於計算機的。數據的邏輯結構分為線性結構和非線性結構,線性表是典型的線性結構;集合、樹和圖是典型的非線性結構。數據的邏輯結構分類見圖1-1。
- 集合結構中的數據元素之間除了 “同屬於一個集合”的關系外,別無其他關系。
- 線性結構結構中的數據元素之間只存在一對一的關系。
- 樹形結構結構中的數據元素之間存在一對多的關系。
- 圖狀結構或網狀結構結構中的數據元素之間存在多對多的關系。
一般來講,一個一元多項式,按照升冪寫成
多項式由(n+1)個系數唯一確定,按照原理上可以用線性表P來表示,實現計算機處理。
2.存儲結構
存儲結構是指數據結構在計算機中的表示(又稱映像),也稱物理結構。它包括數據元素的表示和關系的表示。數據的存儲結構是邏輯結構用計算機語言的實現,它依賴於計算機語言。數據的存儲結構主要有:順序存儲、鏈式存儲、索引存儲和散列存儲。
- 順序存儲:把邏輯上相鄰的元素存儲在物理位置上也相鄰的存儲單元里,元素之間的關系由存儲單元的鄰接關系來體現。其優點是可以實現隨機存取,每個元素占用最少的存儲空間;缺點是只能使用相鄰的一整塊存儲單元,因此可能產生較多的外部碎片。
- 鏈接存儲:不要求邏輯上相鄰的元素在物理位置上也相鄰,借助指示元素存儲地址的指針表示元素之間的邏輯關系。其優點是不會出現碎片現象,充分利用所有存儲單元;缺點是每個元素因存儲指針而占用額外的存儲空間,並且只能實現順序存取。
- 索引存儲:在存儲元素信息的同時,還建立附加的索引表。索引表中的每一項稱為索引項,索引項的一般形式是:(關鍵字,地址)。其優點是檢索速度快;缺點是增加了附加的索引表,會占用較多的存儲空間。另外,在增加和刪除數據時要修改索引表,因而會花費較多的時間。
- 散列存儲:根據元素的關鍵字直接計算出該元素的存儲地址,又稱為Hash存儲。其優點是檢索、增加和刪除結點的操作都很快;缺點是如果散列函數不好可能出現元素存儲單元的沖突,而解決沖突會增加時間和空間開銷。
如果用順序表p[n]進行存儲,下標代表指數,所存儲的值代表系數。這樣便可實現多個一元多項式的相加相減以及求導運算。但是對於處理
就需要開辟長度為1001的線性表,顯然浪費空間。故可以將指數和系數分開存儲。
一般情況下,對於一元n次多項式可以寫成
顯然,可以用一個長度為m且每個元素包含倆個數據項(系數項和指數項)的線性表((p1,e1),(p2,e2),.....,(pn,en))唯一確定多項式p(x)。
線性表有兩種存儲結構,相應的采用線性表表示的一元多項式也有兩種存儲結構。如果只對多項式“求值”等不改變多項式的系數和指數的運算,則可以用順序存儲結構,否則應該采用鏈式存儲結構。本次對一元多項式的操作是相加相減求導運算,故需要使用鏈式存儲結構
比如
如下圖所示,為一元多項式 A(x)=7+3x+9x8+5x17 和 B(x)=8x+22x7-9x8 的鏈表表示圖:
一元多項式的存儲結構定義描述如下:
typedef struct
{
float coef;//系數
int expn;//指數
struct UNARY *next;//指針域
} UNARY;
3.算法設計思想
如果兩個多項式相加(減),根據兩個多項式相加的規則:兩個指數項相同的對應系數相加(減),如果系數和(差)不為零,則和(差)作為系數和指數一起構成“和(差)多項式”;如果兩個系數不同,則分別復制“和(差)多項式”中去。
當兩個一元多項式相加時,需遵循如下的運算規則。假設指針 qa 和qb 分別指向多項式 A 和多項式 B 中當前進行比較的某個結點,則比較兩個結點的指數項,有以下 3 種情況:
- 指針 qa 所指結點的指數值小於指針 qb 所指結點的指數值,則應摘除 qa 所指結點插入到“和多項式”鏈表中去;
- 指針 qa 所指結點的指數值大於指針 qb 所指結點的指數值,則應摘除 qb 所指結點插入到“和多項式”鏈表中去;
- 指針 qa 所指結點的指數值等於指針 qb 所指結點的指數值,則將兩個結點的系數相加:若和不為 0 ,則修改 qa 所指結點的系數值,- 同時釋放qb所指結點;若和為 0,則應從多項式 A 的鏈表中刪除相應結點,並釋放指針 qa 和 qb 所指結點。
如果對多項式進行求導,根據多項式的求導規則:系數與指數相乘,指數減1;如果指數為零,本項為零,不再復制到新的多項式中
4.輸入、輸出設計
輸入設計:
首先對第一個鏈表進行輸入
輸入格式(系數+指數)
每次對是否繼續輸入該鏈表進行輸入判斷
輸入格式(1:繼續 0:結束)
輸入選擇
輸入格式(1:求導,2:加減運算)
輸入運算類型
輸入格式(+/-)
輸出設計:
依次輸出鏈表中的系數和指數
輸出格式(系數+指數)
四、主要代碼
/*
*對一元多項式進行升冪排序
*輸入:一元多項式鏈表
*輸出:升冪排序的一元多項式鏈表
*
*/
UNARY* Increasing(UNARY *LA,UNARY *LB)
{
UNARY *head,*end,*pre,*cur,*next,*temp;
head = LA;//以及LB
end = NULL;
//冒泡排序:將 最小/最大 的節點后移至當前的最后一位。
while(head->next != end)
{
for(pre = head,cur = head->next,next = cur->next; next != end; pre = pre->next,cur = cur->next,next = next->next)
{
if(cur->expn > next->expn)
{
cur->next = next->next;
pre->next = next;
next->next = cur;
temp = next;
next = cur;
cur = temp;
}
}
end = cur;
}
}
float add_ab(float A,float B)
{
return A+B;
}
float subtract_ab(float A,float B)
{
return A - B;
}
//升冪的一元多項式的相加與相減
UNARY* unaryAdd_Sub(UNARY *LA,UNARY *LB,char method)
{
//LA作為輸出鏈
UNARY *r,*s,*p,*q;
int cmp;
p = LA->next;//用於比較
q = LB->next;//用於比較
s = LA;//用於記錄p的前置
r = LB;//用於記錄q的后置
while(p!=NULL && q!=NULL)
{
if(p->expn<q->expn) cmp = -1;//當p指數小於q指數,p后移
else if(p->expn>q->expn) cmp = 1;//當p指數大於q指數,q為p的前置,q后移
else cmp = 0;//pq指數相同,進行加/減運算
switch(cmp)
{
case -1:
{
s = p;
p = p->next;
};
break;
case 0:
{
float x;
if(method == '+')
{
x = add_ab(p->coef,q->coef);
}
else if(method == '-')
{
x = subtract_ab(p->coef,q->coef);
}
if((int)x!=0)
{
p->coef = x;
s = p;
p = p->next;
r->next =q->next;
free(q);
q = r->next;
}
else
{
//刪除LA節點
s->next = p->next;
free(p);
p = s->next;
//刪除LB節點
r->next =q->next;
free(q);
q = r->next;
}
};
break;
case 1:
{
r->next = q->next;
q->next = s->next;
s->next = q;
s = q;
q = r->next;
};
break;
}
}
if(q!=NULL)
{
//因為 前面的結束條件 p = null 所以 p的前置s位於鏈表的尾部,s連接q
s->next = q;
}
free(LB);
return LA;
}
/*對一元多項式進行求導
*輸入:一元多項式鏈表
*輸出:求導后的一元多項式鏈表
*所謂求導:系數與指數相乘,指數減1;如果指數為零,本項為零,不再復制到新的多項式中
*/
UNARY* Derivation(UNARY *LA,UNARY *LB)
{
UNARY *headLA,*headLB;
headLA = LA;
headLB = LB;
while(headLA->next!=NULL)
{
headLA = headLA->next;
headLA->coef = headLA->coef*headLA->expn;
if(headLA->expn!=0)
{
headLA->expn -= 1;
}
else
{
headLA->expn = 0;
}
}
while(headLB->next!=NULL)
{
headLB = headLB->next;
headLB->coef = headLB->coef*headLB->expn;
if(headLB->expn!=0)
{
headLB->expn -= 1;
}
else
{
headLB->expn = 0;
}
}
}
五、程序運行結果截圖
六、遇到的問題和解決方法
問題:剛開始考慮的一元多項式默認是升冪,對於亂序的一元多項式不知道如何解決
解決方法:對亂序的一元多項式進行排序,首先考慮的是值傳遞 但是代碼過於復雜,無論是時間復雜度,還是空間復雜度 都高於地址交換
唯一的好處是邏輯簡單;故本次采用地址交換的方式進行對亂序的一元二次多項式進行升冪排序,主要算法就是冒泡排序;需要6個節點並且是前后繼的關系,每次后移加判斷;
問題:對於’零‘這個特殊項的處理
解決方法:1.如果零系數出現在定義多項式階段,直接不進行連接主鏈表,並且釋放該空間
2.如果零系數出現在加減運算階段,進行刪除兩鏈表節處理,並且釋放該空間
3.如果零指數出現在求導運算階段,刪除節點,並釋放空間
七、完整代碼
點擊查看代碼
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
float coef;//系數
int expn;//指數
struct UNARY *next;
} UNARY;
float add_ab(float A,float B)
{
return A+B;
}
float subtract_ab(float A,float B)
{
return A - B;
}
//升冪的一元多項式的相加與相減
UNARY* unaryAdd_Sub(UNARY *LA,UNARY *LB,char method)
{
//LA作為輸出鏈
UNARY *r,*s,*p,*q;
int cmp;
p = LA->next;//用於比較
q = LB->next;//用於比較
s = LA;//用於記錄p的前置
r = LB;//用於記錄q的后置
while(p!=NULL && q!=NULL)
{
if(p->expn<q->expn) cmp = -1;//當p指數小於q指數,p后移
else if(p->expn>q->expn) cmp = 1;//當p指數大於q指數,q為p的前置,q后移
else cmp = 0;//pq指數相同,進行加/減運算
switch(cmp)
{
case -1:
{
s = p;
p = p->next;
};
break;
case 0:
{
float x;
if(method == '+')
{
x = add_ab(p->coef,q->coef);
}
else if(method == '-')
{
x = subtract_ab(p->coef,q->coef);
}
if((int)x!=0)
{
p->coef = x;
s = p;
p = p->next;
r->next =q->next;
free(q);
q = r->next;
}
else
{
//刪除LA節點
s->next = p->next;
free(p);
p = s->next;
//刪除LB節點
r->next =q->next;
free(q);
q = r->next;
}
};
break;
case 1:
{
r->next = q->next;
q->next = s->next;
s->next = q;
s = q;
q = r->next;
};
break;
}
}
if(q!=NULL)
{
//因為 前面的結束條件 p = null 所以 p的前置s位於鏈表的尾部,s連接q
s->next = q;
}
free(LB);
return LA;
}
UNARY* creatList(UNARY *LA,UNARY *LB)
{
LA->next = NULL;
LB->next = NULL;
UNARY *node;
int choice;
int i = 1;
while(1)
{
printf("輸入LA序列的第%d元素的系數+指數(格式:系數 指數)",i);
node = (UNARY*)malloc(sizeof(UNARY));
if(node==NULL)
{
exit(0);
}
scanf("%f %d",&node->coef,&node->expn);
//不合法分析:1、系數為零 (√)2、指數重復(未解決)
if(node->coef==0)
{
continue;
}
node->next = LA->next;
LA->next = node;
i++;
printf("繼續?(1,0)");
scanf("%d",&choice);
if(choice==0)
{
break;
}
}
while(1)
{
printf("輸入LB序列的第%d元素的系數+指數(格式:系數 指數)",i);
node = (UNARY*)malloc(sizeof(UNARY));
scanf("%f %d",&node->coef,&node->expn);
node->next = LB->next;
LB->next = node;
i++;
printf("繼續?(1,0)");
scanf("%d",&choice);
if(choice==0)
{
break;
}
}
}
UNARY* printList(UNARY *LA,UNARY *LB)
{
UNARY *circleLA,*circleLB;
circleLA = LA;
circleLB = LB;
printf("LA:\n");
while(circleLA->next!=NULL)
{
circleLA = circleLA->next;
printf("%.2f %d\n",circleLA->coef,circleLA->expn);
}
printf("LB:\n");
while(circleLB->next!=NULL)
{
circleLB = circleLB->next;
printf("%.2f %d\n",circleLB->coef,circleLB->expn);
}
}
/*對一元多項式進行升冪排序
*輸入:一元多項式鏈表
*輸出:升冪排序的一元多項式鏈表
*
*/
UNARY* Increasing(UNARY *LA,UNARY *LB)
{
UNARY *head,*end,*pre,*cur,*next,*temp;
head = LA;
end = NULL;
//冒泡排序:將 最小/最大 的節點后移至當前的最后一位。
while(head->next != end)
{
for(pre = head,cur = head->next,next = cur->next; next != end; pre = pre->next,cur = cur->next,next = next->next)
{
if(cur->expn > next->expn)
{
cur->next = next->next;
pre->next = next;
next->next = cur;
temp = next;
next = cur;
cur = temp;
}
}
end = cur;
}
head = LB;
end = NULL;
while(head->next != end)
{
for(pre = head,cur = head->next,next = cur->next; next != end; pre = pre->next,cur = cur->next,next = next->next)
{
if(cur->expn > next->expn)
{
cur->next = next->next;
pre->next = next;
next->next = cur;
temp = next;
next = cur;
cur = temp;
}
}
end = cur;
}
}
/*對一元多項式進行求導
*輸入:一元多項式鏈表
*輸出:求導后的一元多項式鏈表
*所謂求導系數與指數相乘,指數減1;如果指數為零,本項為零,不再復制到新的多項式中
*/
UNARY* Derivation(UNARY *LA,UNARY *LB)
{
UNARY *headLA,*headLB;
headLA = LA;
headLB = LB;
while(headLA->next!=NULL)
{
headLA = headLA->next;
headLA->coef = headLA->coef*headLA->expn;
if(headLA->expn!=0)
{
headLA->expn -= 1;
}
else
{
headLA->expn = 0;
}
}
while(headLB->next!=NULL)
{
headLB = headLB->next;
headLB->coef = headLB->coef*headLB->expn;
if(headLB->expn!=0)
{
headLB->expn -= 1;
}
else
{
headLB->expn = 0;
}
}
}
int main()
{
int choice;
//創建鏈表
UNARY *LA,*LB;
LA = (UNARY*)malloc(sizeof(UNARY));
LB = (UNARY*)malloc(sizeof(UNARY));
creatList(LA,LB);
//將鏈表變為升冪次序
Increasing(LA,LB);
printf("升冪后\n");
printList(LA,LB);
printf("輸入選擇(1:求導 2:運算):");
scanf("%d",&choice);
if(choice ==1)
{
//求導:將系數與指數相乘 然后指數減1
Derivation(LA,LB);
printf("求導后\n");
printList(LA,LB);
}
else if(choice == 2)
{
//運算(加減運算)
char x;
printf("運算:");
scanf("\n");
scanf("%c",&x);
unaryAdd_Sub(LA,LB,x);
printf("運算后\n");
printList(LA,NULL);
}
}
文章主要摘自《深入淺出數據結構與算法》————清華出版社