大二上期資料結構實驗記錄(二)【初版】C實現簡單一元多項式加減乘求導及代值計算(有借鑑刪改)
想要記錄自己程式設計思維的成長所以發到部落格,歡迎並且感激大家指出缺點和錯誤!
一、【實驗構思(Conceive)】
本次實驗要求是用C或C++語言設計並實現一個一元稀疏多項式的簡單計算器,要求是要有如下功能 1、輸入並建立多項式 2、輸出多項式,序列按指數降序排列 3、多項式A(x)和B(x)相加,並建立多項式A(x)+B(x) 4、多項式A(x)和B(x)相減,並建立多項式A(x)-B(x) 5、給定 x 的值,計算多項式 6、多項式A(x)和B(x)相乘,建立多項式A(x)B(x) ( 選做,作為難度B的 操作)
二、【實驗設計(Design)】
-
考慮一元多項式的資料結構(資料物件,資料關係,其上操作)如何表示與實現;
-
具體建立有頭結點的一元多項式的結構實現用結構體實現,一個節點資料有兩個,一個是double,一個是int,分別用來儲存每一項的係數和指數,還有一個指標域的struct型別的指標next,指向下一個結點。
-
用createPolyn(Polyn, int)函式建立名為head的多項式,提示使用者輸入第一個多項式要輸入幾項,createPolyn()函式內呼叫insert()函式,插入輸入的每一項,插入是即排序(序列按指數降序排列)
-
用printPolyn()函式實現列印,要分為多種情況: 1.係數大於0用‘+’連線,本身無符號,小於0的負數本身有符號‘-’,就不理會。 2.若係數為0,此項就為0 3.若係數不為0, 1)為1,不列印係數1: 指數為0,列印‘1’ 指數為1,列印‘X’ 2)為-1,不列印1,只打印‘-’ 指數為0,列印‘-1’ 指數為1,列印’-X’ 3)其他數,列印‘係數X^指數
-
addPolyn()函式實現:用新連結串列hc來存結果,計算過程中,用cmp()函式比較兩當前指標所指節點的指數大小,經過比較,決定是直接插入hc還是相加兩節點係數值再判斷是否為0後插入hc或者釋放係數為0的節點,經過一次節點計算後,據情況指標後移。
-
subPolyb()函式即將第=減數多項式取反再呼叫addPolyn(),將取反後的多項式與原被減數多項式相加。
-
multiPolyn()函式實現:用新連結串列hc來存結果,計算過程中,第一個多項式的每一項都要去乘第二個多項式的所有項然後相加之和,有巢狀for迴圈實現,內層迴圈每次建立新hc節點來儲存並插入結果。
-
derivation()求導函式實現,即將每一個指數不為0的項的係數指數重新賦值,係數=係數*指數 ,指數=指數- 1。
-
valueCount()函式的實現,輸入X的值,再將其代入計算即得結果,同時計算輸入的多項式a和b。
-
destroyPolyn()函式,每次結束一次操作就將多項式進行銷燬,具體操作為節點存在即釋放,銷燬成功即返回OK,多項式不存在銷燬失敗,即返回FAILED。
-
cmp()函式用來比較兩多項式中指標當前所指項係數大小.
三、【實現(Implement)】
抽象資料型別實現程式碼:
typedef struct lNode{
double coef;//多項式的係數
int expn;//多項式的指數
struct lNode *next;//指向下一個多項式的結點的指標
}*Polyn,Polynomial;
操作函式宣告:
//操作函式宣告
void Insert(Polyn, Polyn); //
Polyn createPolyn(Polyn,int);//建立一個頭結點為head、項數為m的一元多項式
status destroyPolyn(Polyn);//銷燬一元稀疏多項式連結串列,程式結束前應呼叫此函式釋放多項式連結串列記憶體
void printPolyn(Polyn);//注意列印分類
//實現多項式的加減乘,求導
Polyn addPolyn(Polyn, Polyn);
Polyn subPolyn(Polyn, Polyn);
Polyn multiPolyn(Polyn, Polyn);
Polyn derivation(Polyn);
int cmp(Polyn, Polyn);
int valueCount(Polyn, int);
函式定義
status destroyPolyn(Polyn HEAD){//銷燬存在的多項式連結串列
Polyn h, q = HEAD;
if(h == NULL)
return FAILED;
while(q){//迴圈銷燬連結串列
Polyn p = q;
q = q -> next;
free(p);
}
return OK;
}
Polyn createPolyn(Polyn HEAD, int n){//輸入m項的係數和指數,建立表示一元多項式的有序連結串列
int i;
Polyn p;
p = HEAD = (Polyn)malloc(sizeof(Polyn));
HEAD->next = NULL;
for(i = 0; i < n; i++)
{
p = (Polyn)malloc(sizeof(Polyn));//建立新結點以接收資料
printf("請輸入第%d項的係數與指數(輸入一個數就按回車):\n", i+1);
scanf("%lf %d", &p->coef, &p->expn);//注意double型別接收說明是%lf
Insert(p, HEAD); //呼叫Insert函式插入結點 將p節點插入連結串列HEAD中
}
return HEAD;
}
void Insert(Polyn p,Polyn HEAD){ //插入一項 就立刻排序 (插入演算法)
if(p->coef == 0)
free(p);//係數為0的話沒意義釋放結點
else
{
Polyn q1,q2;
q1 = HEAD;//q1指向頭結點
q2 = HEAD -> next;//q2指向第一個結點(也就是多項式第一項)
while(q2 && p->expn < q2->expn)//條件是q2指向的那一項 存在 且p輸入的這一項的指數小於q2指向的那一項的指數(指數按從大到小排序)
{//查詢插入位置
q1=q2;//q1指向下一項
q2=q2->next;//q2指向下一項
}
if(q2 && p->expn == q2->expn)
{//將指數相同相合並
q2->coef += p->coef;
free(p);//釋放被合併的一項
if(!q2->coef) //若合併後原來的節點係數為O了也就釋放原來的結點
{
q1->next = q2->next;
free(q2);
}
}
else
{//指數為新時將結點插入q1與q2之間
p->next = q2;
q1->next = p;
}
}
}
void printPolyn(Polyn HEAD){//在過程中使用,或者主函式呼叫
Polyn q;
q = HEAD->next;
int count;
count = 0;
if(!q){
printf("0\n");
return;
}
while(q){
if(q->coef > 0 && count != 0)//係數大於0的情況
printf("+");
if(q->coef != 1 && q->coef != -1){//係數不為正負一不需要特殊處理
printf("%.5f", q->coef);
if(q->expn == 1)
printf("X");
else if (q->expn)
printf("X^%d", q->expn);
}
else{
if(q->coef == 1){//係數為正負一需要特殊處理
if(!q->expn)
printf("1");
else if(q->expn == 1)
printf("X");
else
printf("X^%d", q->expn);
}
if(q->coef == -1){
if(!q->expn)
printf("-1");
else if(q->expn == 1)
printf("-X");
else
printf("-X^%d", q->expn);
}
}
q = q->next;
count++;
}
printf("\n");
}
int cmp(Polyn a, Polyn b){//計算過程中會用到的比較
if(a&&b){
if(!b || a->expn > b->expn) return 1;
else if(!a || a->expn < b->expn) return -1;
else return 0;
}
else if(!a && b)
return -1;//a多項式已空,但b多項式非空
else
return 1;//b多項式已空,但a多項式非空
}
Polyn addPolyn(Polyn ha, Polyn hb){
Polyn qa = ha->next;
Polyn qb = hb->next;
Polyn headc,hc,qc;
hc = (Polyn)malloc(sizeof(Polynomial));//建立頭結點
hc->next = NULL;
headc = hc;
while(qa || qb)
{
qc = (Polyn)malloc(sizeof(Polynomial));
switch(cmp(qa,qb)){//比較qa和qb指標所指的兩個節點
case 1://A的指數大於B的指數
{
qc->coef=qa->coef;//存qa
qc->expn=qa->expn;
qa=qa->next;//qa指標後移
break;
}
case 0://A的指數等於B的指數
{
qc->coef=qa->coef+qb->coef;//係數相加
qc->expn=qa->expn;//隨便存個指數
qa=qa->next;//qa後移
qb=qb->next;//qb後移
break;
}
case -1://A的指數小於B的指數
{
qc->coef=qb->coef;//存qb
qc->expn=qb->expn;
qb=qb->next;//qb指標後移
break;
}
}
if(qc->coef!=0)//加法得到的新的QC結點係數不為0就將結點頭插
{
qc->next=hc->next;
hc->next=qc;
hc=qc;
}
else free(qc);//當相加係數為0時,釋放該結點
}
return headc;
}
Polyn subPolyn(Polyn ha, Polyn hb){
Polyn h = hb;
Polyn p = hb->next;
Polyn hd;
while(p)
{
p->coef *= -1;//將hb的係數取反,為了利用加法
p = p->next;
}
hd = addPolyn(ha, h);
for(p = h->next; p; p = p->next) //恢復hb的係數
p->coef *= -1;
return hd;
}
Polyn multiPolyn(Polyn ha, Polyn hb){//求解並建立多項式hf,返回其頭指標
Polyn hf,pf;
Polyn qa = ha->next;
Polyn qb = hb->next;
hf = (Polyn)malloc(sizeof(Polynomial));//建立頭結點
hf->next = NULL;
for(; qa; qa = qa->next)//巢狀迴圈,結果為qa的每一項要去乘qb的所有項的和
{
for(qb = hb->next; qb; qb = qb->next)
{
pf = (Polyn)malloc(sizeof(Polynomial));//建立新節點來插入hf
pf->coef = qa->coef * qb->coef;
pf->expn = qa->expn + qb->expn;
Insert(pf,hf);//呼叫Insert函式以插入並且合併指數相同的項
}
}
return hf;
}
Polyn derivation(Polyn HEAD){//求解並建立導函式多項式,並返回其頭指標
Polyn q = HEAD->next;
Polyn p1, p2, hd;
hd = p1 = (Polyn)malloc(sizeof(Polynomial));//建立頭結點
hd->next = NULL;
while(q){
if(q->expn != 0)//指數不為0時
{ //該項不是常數項時
p2 = (Polyn)malloc(sizeof(Polynomial));
p2->coef = q->coef*q->expn;//新的係數等於舊的係數和指數相乘
p2->expn = q->expn - 1;//新的指數等於舊的指數減一
p2->next = p1->next;//連線結點
p1->next = p2;
p1 = p2;
}
q = q->next;
}
return hd;
}
int valueCount(Polyn HEAD, int x){//求解指定X值的多項式的值
Polyn q, h;
q = h = HEAD;
q = h->next;
int result = 0;
while(q){
result += q->coef * pow(x, q->expn);
q = q->next;
}
return result;
}
四、【測試結果(Testing)】
五、【實驗總結】
這次實驗感覺比上一次對我的考驗大,才發現很多程式我能看懂,但是當自己寫就很難真的寫出來,實際上機經驗太少,是我的弱點。通過本次實驗,我也對連結串列的理解與使用更為深刻和熟悉了,比如說建立head為頭結點的新連結串列,對有頭結點的連結串列的操作,插入結點函式的實現,插入立即排序,以便計算和列印,四個計算中加法和乘法算有技巧,減法就是取反相加,求導就是代入公式,計算多項式的值也是,加法的指標使用最體現連結串列的操作,主函式也花了不少時間寫合法性檢查,和計算操作的迴圈,是結束本次操作,還是退出程式,在除錯的過程中發現多處可新增合法性檢查。比如項數要為整型大於等於1,指數和係數要分別為整型和雙精度,操作序號為整型,若輸入不合法就重新輸入。
六、思考題或【專案運作描述(Operate)】
無
七、【原始碼】
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#define OK 1
#define FAILED 0
typedef int status;
//定義多項式的項儲存結構,每一個結點對應稀疏多項式中的一項
typedef struct lNode{
double coef;//多項式的係數
int expn;//多項式的指數
struct lNode *next;//指向下一個多項式的結點的指標
}*Polyn,Polynomial;
//操作函式宣告
void Insert(Polyn, Polyn); //
Polyn createPolyn(Polyn,int);//建立一個頭結點為head、項數為m的一元多項式
status destroyPolyn(Polyn);//銷燬一元稀疏多項式連結串列,程式結束前應呼叫此函式釋放多項式連結串列記憶體
void printPolyn(Polyn);//注意列印分類
//實現多項式的加減乘,求導
Polyn addPolyn(Polyn, Polyn);
Polyn subPolyn(Polyn, Polyn);
Polyn multiPolyn(Polyn, Polyn);
Polyn derivation(Polyn);
int cmp(Polyn, Polyn);
int valueCount(Polyn, int);
//主函式
int main(void){
int m, n, x, y;
int a;
int flag;
Polyn ha = 0,hb = 0, pc;
printf(" 歡迎使用多項式簡單操作程式\n\n");
while(a != 0){
printf("請輸入a的項數:");
y = scanf("%d",&m);
while(!y || m <= 0){//合法性檢查
fflush(stdin);
printf("輸入錯誤請重新輸入\n");
printf("請輸入a的項數:");
y = scanf("%d",&m);
}
ha=createPolyn(ha,m);//建立多項式a
printf("請輸入b的項數:");
y = scanf("%d",&n);
while(!y || n <= 0){//合法性檢查
fflush(stdin);
printf("輸入錯誤請重新輸入\n");
printf("請輸入b的項數:");
y = scanf("%d",&n);
}
hb=createPolyn(hb,n);//建立多項式b
//輸出選單
printf(" **********************************************************************\n");
printf(" * 多項式操作程式 *\n");
printf(" * *\n");
printf(" * 1:輸出多項式a 2:輸出多項式b *\n");
printf(" * *\n");
printf(" * 3:輸出a的導數 4:輸出b的導數 *\n");
printf(" * *\n");
printf(" * 5:輸出a+b 6:輸出a-b *\n");
printf(" * *\n");
printf(" * 7:輸出a*b 8:退出此次操作 *\n");
printf(" * *\n");
printf(" * 9:退出程式 10:輸入未知數的值計算多項式的值*\n");
printf(" **********************************************************************\n");
a = 1;//好進行跳出迴圈的判斷
while(a == 1){
y = scanf("%d",&flag);
while(!y){//合法性檢查
fflush(stdin);
printf("輸入錯誤請重新輸入\n");
printf("請輸入運算元:");
y = scanf("%d",&flag);
}
switch(flag)
{
case 1:
{
printf(" 多項式a=");
printPolyn(ha);
break;
}
case 2:
{
printf(" 多項式b=");
printPolyn(hb);
break;
}
case 3:
{
pc = derivation(ha);
printf(" 多項式a的導函式為:a'=");
printPolyn(pc);
break;
}
case 4:
{
pc = derivation(hb);
printf(" 多項式b的導函式為:b'=");
printPolyn(pc);
break;
}
case 5:
{
pc = addPolyn(ha,hb);
printf(" a+b=");
printPolyn(pc);
break;
}
case 6:
{
pc = subPolyn(ha,hb);
printf(" a-b=");
printPolyn(pc);
break;
}
case 7:
{
pc = multiPolyn(ha, hb);
printf(" a*b=");
printPolyn(pc);
break;
}
case 8:
{
printf(" 此次操作結束!請重新輸入多項式\n");
destroyPolyn(ha);
destroyPolyn(hb);
a = -1;
break;
}
case 9:
{
int l = destroyPolyn(ha);
int k = destroyPolyn(hb);
if(l == 1 && k == 1)
printf("銷燬成功\n");
else
printf("銷燬失敗\n");
printf("即將退出\n");
return 0;
}
case 10:
{
int x, y;
printf("請輸入未知數X的值\n");
y = scanf("%d", &x );
while(!y){
fflush(stdin);
printf("輸入有誤請重新輸入\n");
y = scanf("%d", &x );
}
printf("多項式a的值為%d\n", valueCount(ha, x));
printf("多項式b的值為%d\n", valueCount(hb, x));
break;
}
default:
printf(" 您的選擇錯誤,請重新選擇運算元!\n");
}
}
}
return 0;
}
//函式定義
status destroyPolyn(Polyn HEAD){//銷燬存在的多項式連結串列
Polyn h, q = HEAD;
if(h == NULL)
return FAILED;
while(q){//迴圈銷燬連結串列
Polyn p = q;
q = q -> next;
free(p);
}
return OK;
}
Polyn createPolyn(Polyn HEAD, int n){//輸入m項的係數和指數,建立表示一元多項式的有序連結串列
int i;
Polyn p;
p = HEAD = (Polyn)malloc(sizeof(Polyn));
HEAD->next = NULL;
for(i = 0; i < n; i++)
{
p = (Polyn)malloc(sizeof(Polyn));//建立新結點以接收資料
printf("請輸入第%d項的係數與指數(輸入一個數就按回車):\n", i+1);
scanf("%lf %d", &p->coef, &p->expn);//注意double型別接收說明是%lf
Insert(p, HEAD); //呼叫Insert函式插入結點 將p節點插入連結串列HEAD中
}
return HEAD;
}
void Insert(Polyn p,Polyn HEAD){ //插入一項 就立刻排序 (插入演算法)
if(p->coef == 0)
free(p);//係數為0的話沒意義釋放結點
else
{
Polyn q1,q2;
q1 = HEAD;//q1指向頭結點
q2 = HEAD -> next;//q2指向第一個結點(也就是多項式第一項)
while(q2 && p->expn < q2->expn)//條件是q2指向的那一項 存在 且p輸入的這一項的指數小於q2指向的那一項的指數(指數按從大到小排序)
{//查詢插入位置
q1=q2;//q1指向下一項
q2=q2->next;//q2指向下一項
}
if(q2 && p->expn == q2->expn)
{//將指數相同相合並
q2->coef += p->coef;
free(p);//釋放被合併的一項
if(!q2->coef) //若合併後原來的節點係數為O了也就釋放原來的結點
{
q1->next = q2->next;
free(q2);
}
}
else
{//指數為新時將結點插入q1與q2之間
p->next = q2;
q1->next = p;
}
}
}
void printPolyn(Polyn HEAD){//在過程中使用,或者主函式呼叫
Polyn q;
q = HEAD->next;
int count;
count = 0;
if(!q){
printf("0\n");
return;
}
while(q){
if(q->coef > 0 && count != 0)//係數大於0的情況
printf("+");
if(q->coef != 1 && q->coef != -1){//係數不為正負一不需要特殊處理
printf("%.5f", q->coef);
if(q->expn == 1)
printf("X");
else if (q->expn)
printf("X^%d", q->expn);
}
else{
if(q->coef == 1){//係數為正負一需要特殊處理
if(!q->expn)
printf("1");
else if(q->expn == 1)
printf("X");
else
printf("X^%d", q->expn);
}
if(q->coef == -1){
if(!q->expn)
printf("-1");
else if(q->expn == 1)
printf("-X");
else
printf("-X^%d", q->expn);
}
}
q = q->next;
count++;
}
printf("\n");
}
int cmp(Polyn a, Polyn b){//計算過程中會用到的比較
if(a&&b){
if(!b || a->expn > b->expn) return 1;
else if(!a || a->expn < b->expn) return -1;
else return 0;
}
else if(!a && b)
return -1;//a多項式已空,但b多項式非空
else
return 1;//b多項式已空,但a多項式非空
}
Polyn addPolyn(Polyn ha, Polyn hb){
Polyn qa = ha->next;
Polyn qb = hb->next;
Polyn headc,hc,qc;
hc = (Polyn)malloc(sizeof(Polynomial));//建立頭結點
hc->next = NULL;
headc = hc;
while(qa || qb)
{
qc = (Polyn)malloc(sizeof(Polynomial));
switch(cmp(qa,qb)){//比較qa和qb指標所指的兩個節點
case 1://A的指數大於B的指數
{
qc->coef=qa->coef;//存qa
qc->expn=qa->expn;
qa=qa->next;//qa指標後移
break;
}
case 0://A的指數等於B的指數
{
qc->coef=qa->coef+qb->coef;//係數相加
qc->expn=qa->expn;//隨便存個指數
qa=qa->next;//qa後移
qb=qb->next;//qb後移
break;
}
case -1://A的指數小於B的指數
{
qc->coef=qb->coef;//存qb
qc->expn=qb->expn;
qb=qb->next;//qb指標後移
break;
}
}
if(qc->coef!=0)//加法得到的新的QC結點係數不為0就將結點頭插
{
qc->next=hc->next;
hc->next=qc;
hc=qc;
}
else free(qc);//當相加係數為0時,釋放該結點
}
return headc;
}
Polyn subPolyn(Polyn ha, Polyn hb){
Polyn h = hb;
Polyn p = hb->next;
Polyn hd;
while(p)
{
p->coef *= -1;//將hb的係數取反,為了利用加法
p = p->next;
}
hd = addPolyn(ha, h);
for(p = h->next; p; p = p->next) //恢復hb的係數
p->coef *= -1;
return hd;
}
Polyn multiPolyn(Polyn ha, Polyn hb){//求解並建立多項式hf,返回其頭指標
Polyn hf,pf;
Polyn qa = ha->next;
Polyn qb = hb->next;
hf = (Polyn)malloc(sizeof(Polynomial));//建立頭結點
hf->next = NULL;
for(; qa; qa = qa->next)//巢狀迴圈,結果為qa的每一項要去乘qb的所有項的和
{
for(qb = hb->next; qb; qb = qb->next)
{
pf = (Polyn)malloc(sizeof(Polynomial));//建立新節點來插入hf
pf->coef = qa->coef * qb->coef;
pf->expn = qa->expn + qb->expn;
Insert(pf,hf);//呼叫Insert函式以插入並且合併指數相同的項
}
}
return hf;
}
Polyn derivation(Polyn HEAD){//求解並建立導函式多項式,並返回其頭指標
Polyn q = HEAD->next;
Polyn p1, p2, hd;
hd = p1 = (Polyn)malloc(sizeof(Polynomial));//建立頭結點
hd->next = NULL;
while(q){
if(q->expn != 0)//指數不為0時
{ //該項不是常數項時
p2 = (Polyn)malloc(sizeof(Polynomial));
p2->coef = q->coef*q->expn;//新的係數等於舊的係數和指數相乘
p2->expn = q->expn - 1;//新的指數等於舊的指數減一
p2->next = p1->next;//連線結點
p1->next = p2;
p1 = p2;
}
q = q->next;
}
return hd;
}
int valueCount(Polyn HEAD, int x){//求解指定X值的多項式的值
Polyn q, h;
q = h = HEAD;
q = h->next;
int result = 0;
while(q){
result += q->coef * pow(x, q->expn);
q = q->next;
}
return result;
}