一元多項式的乘法與加法運算
設計函數分別求兩個一元多項式的乘積與和。
輸入格式:
輸入分2行,每行分別先給出多項式非零項的個數,再以指數遞降方式輸入一個多項式非零項系數和指數(絕對值均為不超過1000的整數)。數字間以空格分隔。
輸出格式:
輸出分2行,分別以指數遞降方式輸出乘積多項式以及和多項式非零項的系數和指數。數字間以空格分隔,但結尾不能有多余空格。零多項式應輸出0 0。
輸入樣例:
4 3 4 -5 2 6 1 -2 0 3 5 20 -7 4 3 1
輸出樣例:
15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1 5 20 -4 4 -5 2 9 1 -2 0
解題思路
這道題目不算太難,就是代碼比較長。下面會給出這道題最直接簡單的解法。
首先,我們是通過鏈表的形式來存儲多項式,每一個鏈表節點包含有系數,指數,以及指向下一個節點的指針。
1 struct LNode{ 2 int coef, exp; 3 LNode *next; 4 };
我們的main函數如下:
1 int main() { 2 LNode *L1 = creatList(); // 創建第1個多項式 3 LNode *L2 = creatList(); // 創建第2個多項式 4 5 printList(polyMult(L1, L2)); // 兩個多項式求和,並打印輸出 6 printList(polyAdd(L1, L2)); // 兩個多項式相乘,並打印輸出 7 8 return 0; 9 }
其中,creatList函數是用來創建一個鏈表,函數代碼如下:

LNode *creatList() { int n; scanf("%d", &n); LNode *head = new LNode; // 為頭指針設立一個頭節點 head->next = NULL; LNode *p = head; while (n--) { LNode *q = new LNode; q->next = NULL; scanf("%d %d", &q->coef, &q->exp); p = p->next = q; } return head; }
需要注意的是,我們的鏈表都帶有頭指針。
下面來講解polyAdd函數。

LNode *polyAdd(LNode *L1, LNode *L2) { // 讓指針后移一個單位,指向第一個存放數據的節點 L1 = L1->next; L2 = L2->next; // 創建一個求和鏈表 LNode *head = new LNode; head->next = NULL; // 指向求和鏈表的最后一個節點,通過尾插法來插入新節點 LNode *p = head; while (L1 && L2) { LNode *q = new LNode; q->next = NULL; // L1所指向節點的exp大於L2所指向節點的exp if (L1->exp > L2->exp) { q->coef = L1->coef; q->exp = L1->exp; p = p->next = q; L1 = L1->next; } // L2所指向節點的exp大於L1所指向節點的exp else if (L1->exp < L2->exp) { q->coef = L2->coef; q->exp = L2->exp; p = p->next = q; L2 = L2->next; } // L2所指向節點的exp等於L1所指向節點的exp else { q->coef = L1->coef + L2->coef; q->exp = L1->exp; // 系數求和后為0,不需要插入,同時把申請的節點釋放掉 if (q->coef == 0) delete q; // 系數不為零就要插入 else p = p->next = q; L1 = L1->next; L2 = L2->next; } } // 找到不為空的那個多項式 LNode *L = L1 ? L1 : L2; // 把不為空的多項式剩余的節點都接到求和鏈表的后面 while (L) { p = p->next = L; L = L->next; } return head; }
由於鏈表帶有頭節點,所以先讓指針后移一個單位,指向第一個存放數據的節點。
然后我們需要創建一個鏈表,用來存儲兩個多項式相加后的結果。
之后我們進入循環,來進行多項式的相加,循環的條件是兩個多項式都存在,不為空。
由於題目的要求是按指數遞降方式輸出,所以我們按下面的判斷規則來把相加的結果插入到新的鏈表中。
1.如果L1所指向節點的exp大於L2所指向節點的exp,也就是L1 -> exp > L2 -> exp,則不需要相加,只需要把L1所指向節點的coef和exp拷貝到新的節點中,然后把新節點插入到求和的鏈表中。同時,還要讓L1指針向后移動一個位置。
2.如果L2所指向節點的exp大於L1所指向節點的exp,也就是L2 -> exp > L1 -> exp,則不需要相加,只需要把L2所指向節點的coef和exp拷貝到新的節點中,然后把新節點插入到求和的鏈表中。同時,還要讓L2指針向后移動一個位置。
3.如果L2所指向節點的exp等於L1所指向節點的exp,也就是L2 -> exp == L1 -> exp,我們就需要對兩個這節點的coef進行相加,把相加的結果存放到新節點的coef中,同時也要把當前的exp存放到新節點中。再來對相加后的coef進行判斷,如果相加后的coef == 0,那么就不需要把它插入到求和的鏈表中,同時把新節點通過關鍵字delete刪除。如果相加后的coef != 0,我們就把新節點插入到求和的鏈表中。最后,別忘了讓L1和L2向后移動一個位置。
當退出循環后,說明其中一個多項式已經為空了,這個時候我們只需要找到那個還沒有空的多項式,然后把該多項式剩余的那部分節點都接到求和鏈表的后面,就完成了兩個多項式求和這個過程了。當然,如果退出時兩個多項式都為空了,我們同樣可以把其中的一個多項式接到求和鏈表的后面,只不過這個時候接的是NULL。
下面來是polyMult函數。

LNode *polyMult(LNode *L1, LNode *L2) { // 讓指針后移一個單位,指向第一個存放數據的節點 L1 = L1->next; L2 = L2->next; // 創建一個求積鏈表 LNode *head = new LNode; head->next = NULL; while (L1) { // 由於在內層循環中L2指針會改變,需要用headOfL2來保存第二個多項式鏈表的首地址 LNode *headOfL2 = L2; while (L2) { LNode *p = new LNode; p->next = NULL; // 新節點存放多項式相乘的結果 p->coef = L1->coef * L2->coef; p->exp = L1->exp + L2->exp; // 從頭開始遍歷求積鏈表,找到指數比新節點小的那個節點,返回那個節點的前一個節點的地址 LNode *pre = head; while (pre->next && pre->next->exp > p->exp) { pre = pre->next; } // pre->next == NULL或者pre->next->exp < p->exp,直接插入就可以了 if (pre->next == NULL || pre->next->exp < p->exp) { p->next = pre->next; pre->next = p; } // pre->next->exp == p->exp,不需要插入新節點,要判斷是否需要刪除求積鏈表中指數相同的那個節點 else { // 指數相同的兩個節點進行系數相加 pre->next->coef += p->coef; // 如果系數為零,就要刪除那個節點 if (pre->next->coef == 0) { LNode *temp = pre->next; pre->next = temp->next; delete temp; } // 無論怎么樣都不需要把新節點插入,把它釋放放 delete p; } L2 = L2->next; } // 讓L2重新指向第二個多項式鏈表的表頭 L2 = headOfL2; L1 = L1 >next; } return head; }
我們通過逐項相乘的方法來實現兩個多項式的求和。比如說,對於x2 - 1和x + x2 + 1這兩個多項式,我們先讓第一個多項式中的x2去乘第二個多項式的每一項,得到x3 + x4 + x2,把結果插入到求積的鏈表中,然后再讓第一個多項式中的下一個項-1去乘第二個多項式的每一項,得到多項式-x - x2 - 1。當然,在程序中我們不是先把結果算出來再插入到求積鏈表中,而是每計算一次,就把該結果插入到求積鏈表中。所以,真正難的地方就在於,如何把計算結果插入到求積鏈表中,同時保證我們的結果是按指數遞降的方式存放的。
來看我們的程序,為了實現上面說的逐項相乘,首先我們需要一個嵌套循環。外層循環的條件是第一個多項式不為空,內層循環的條件是第二個多項式不為空。這樣我們就實現了用第一個多項式的每一項去乘以第個多項式的每一項。
我們是在內層的循環中進行多項式相乘計算,以及插入操作。
先把多項式相乘后的coef和exp存放到新節點中,然后把它插入到求積鏈表中。
什么時候插入呢?就是在求積鏈表中找到那個指數exp比新節點的指數exp小的那個節點,然后我們把新節點的插入到那個指數exp比它小的節點之前就可以了。
所以,為了把新節點插入到該節點的前面,我們應該通過一個循環來遍歷找到該節點的前驅,也就是說找到該節點的前一個節點。不然如果我們只得到該節點的地址,是不可以把新節點插入到該節點的前面的。所以我們通過pre這個指針來存放前一個節點的地址。並通過pre -> next來表示前一個節點的下一個節點,也就是需要與新節點進行比較的節點。循環的條件就是進行比較的節點不為空,也就是pre -> next != NULL,以及進行比較的節點的指數exp大於新節點的指數exp,也就是pre -> next -> next > p -> exp。
退出循環有三種可能,第一種是pre -> next == NULL,也就是說,新節點的指數比求積鏈表中的任何一個節點的指數都要小,我們直接把新節點插入到表尾就可以了。
第二種是pre -> next -> exp < p -> exp,我們找到了比新節點指數小的節點,並得到了該節點的前一個節點的地址,我們就可以把新節點插入到比它指數小的那個節點的前面。
第三種是pre-> next -> exp == p -> exp,由於指數都一樣,這個時候我們就要進行系數相加,並對相加的結果加以判斷。如果相加后的系數為零,那么我們應該去除掉這一項,在求積鏈表中把該節點釋放掉。如果不為零,就直接在求積鏈表中修改該節點的系數就可以了,不需要把新節點插入到求積鏈表中。
最后是printList函數。

void printList(LNode *L) { // 這個if語句的作用是,如果傳入的多項式為空,為了讓它也有東西可以輸出,我們應該為他加入0,0這個項 if (L->next == NULL) { LNode *p = new LNode; p->next = NULL; p->coef = p->exp = 0; L->next = p; } L = L->next; while (L) { printf("%d %d", L->coef, L->exp); if (L->next) putchar(' '); else putchar('\n'); L = L->next; } }
好了到此為止,我們已經把一元多項式的乘法與加法運算這個問題解決了,下面給出完整的代碼。
完整代碼
1 #include <cstdio> 2 3 struct LNode{ 4 int coef, exp; 5 LNode *next; 6 }; 7 8 LNode *creatList(); 9 void printList(LNode *L); 10 LNode *polyAdd(LNode *L1, LNode *L2); 11 LNode *polyMult(LNode *L1, LNode *L2); 12 13 int main() { 14 LNode *L1 = creatList(); 15 LNode *L2 = creatList(); 16 17 printList(polyMult(L1, L2)); 18 printList(polyAdd(L1, L2)); 19 20 return 0; 21 } 22 23 LNode *creatList() { 24 int n; 25 scanf("%d", &n); 26 27 LNode *head = new LNode; 28 head->next = NULL; 29 LNode *p = head; 30 31 while (n--) { 32 LNode *q = new LNode; 33 q->next = NULL; 34 scanf("%d %d", &q->coef, &q->exp); 35 p = p->next = q; 36 } 37 38 return head; 39 } 40 41 void printList(LNode *L) { 42 if (L->next == NULL) { 43 LNode *p = new LNode; 44 p->next = NULL; 45 p->coef = p->exp = 0; 46 L->next = p; 47 } 48 49 L = L->next; 50 while (L) { 51 printf("%d %d", L->coef, L->exp); 52 if (L->next) putchar(' '); 53 else putchar('\n'); 54 55 L = L->next; 56 } 57 } 58 59 LNode *polyAdd(LNode *L1, LNode *L2) { 60 L1 = L1->next; 61 L2 = L2->next; 62 63 LNode *head = new LNode; 64 head->next = NULL; 65 LNode *p = head; 66 67 while (L1 && L2) { 68 LNode *q = new LNode; 69 q->next = NULL; 70 71 if (L1->exp > L2->exp) { 72 q->coef = L1->coef; 73 q->exp = L1->exp; 74 p = p->next = q; 75 L1 = L1->next; 76 } 77 else if (L1->exp < L2->exp) { 78 q->coef = L2->coef; 79 q->exp = L2->exp; 80 p = p->next = q; 81 L2 = L2->next; 82 } 83 else { 84 q->coef = L1->coef + L2->coef; 85 q->exp = L1->exp; 86 87 if (q->coef == 0) delete q; 88 else p = p->next = q; 89 90 L1 = L1->next; 91 L2 = L2->next; 92 } 93 } 94 95 LNode *L = L1 ? L1 : L2; 96 while (L) { 97 p = p->next = L; 98 L = L->next; 99 } 100 101 return head; 102 } 103 104 LNode *polyMult(LNode *L1, LNode *L2) { 105 L1 = L1->next; 106 L2 = L2->next; 107 108 LNode *head = new LNode; 109 head->next = NULL; 110 111 while (L1) { 112 LNode *headOfL2 = L2; 113 114 while (L2) { 115 LNode *p = new LNode; 116 p->next = NULL; 117 p->coef = L1->coef * L2->coef; 118 p->exp = L1->exp + L2->exp; 119 120 LNode *pre = head; 121 while (pre->next && pre->next->exp > p->exp) { 122 pre = pre->next; 123 } 124 if (pre->next == NULL || pre->next->exp < p->exp) { 125 p->next = pre->next; 126 pre->next = p; 127 } 128 else { 129 pre->next->coef += p->coef; 130 if (pre->next->coef == 0) { 131 LNode *temp = pre->next; 132 pre->next = temp->next; 133 delete temp; 134 } 135 delete p; 136 } 137 138 L2 = L2->next; 139 } 140 141 L2 = headOfL2; 142 L1 = L1->next; 143 } 144 145 return head; 146 }
擴展
我們來擴展一下,題目是以指數遞降方式輸入一個多項式非零項系數和指數,我們來改變一下輸入的條件。就是,我們不要求以指數遞降方式來輸入,可以隨便輸入,但要求輸入完成后,多項式是以指數遞降的方式來排序的。我們只需要對creatList函數稍微改寫就可以了。
LNode *creatList() { int n; scanf("%d", &n); LNode *head = new LNode; head->next = NULL; while (n--) { LNode *p = new LNode; p->next = NULL; scanf("%d %d", &p->coef, &p->exp); LNode *pre = head; while (pre->next && pre->next->exp > p->exp) { pre = pre->next; } p->next = pre->next; pre->next = p; } return head; }
有沒有發現,插入的過程和上面多項式求積后插入很像,其實他們的原理是一樣的。這樣子,我們就不需要按照指數遞降的順序來輸入,也可以實現指數遞降得順序輸出。