詳解線性結構 —— 一元多項式的乘法與加法運算

onlyblues發表於2021-03-14

原題

設計函式分別求兩個一元多項式的乘積與和。

輸入格式:

輸入分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函式是用來建立一個連結串列,函式程式碼如下:

詳解線性結構 —— 一元多項式的乘法與加法運算
 1 LNode* creatList() {
 2     int n;
 3     scanf("%d", &n);
 4 
 5     LNode *head = new LNode;    // 為頭指標設立一個頭節點
 6     head -> next = NULL;
 7     LNode *p = head;
 8 
 9     while (n--) {
10         LNode *q = new LNode;
11         q -> next = NULL;
12         scanf("%d %d", &q -> coef, &q -> exp);
13         p = p -> next = q;
14     }
15 
16     return head;
17 }
creatList

  需要注意的是,我們的連結串列都帶有頭指標。

  下面來講解polyAdd函式。

詳解線性結構 —— 一元多項式的乘法與加法運算
 1 LNode* polyAdd(LNode *L1, LNode *L2) {
 2     // 讓指標後移一個單位,指向第一個存放資料的節點
 3     L1 = L1 -> next;
 4     L2 = L2 -> next;
 5 
 6     // 建立一個求和連結串列
 7     LNode *head = new LNode;
 8     head -> next = NULL;
 9     // 指向求和連結串列的最後一個節點,通過尾插法來插入新節點
10     LNode *p = head;
11 
12     while (L1 && L2) {
13         LNode *q = new LNode;
14         q -> next = NULL;
15 
16         // L1所指向節點的exp大於L2所指向節點的exp
17         if (L1 -> exp > L2 -> exp) {
18             q -> coef = L1 -> coef;
19             q -> exp = L1 -> exp;
20             p = p -> next = q;
21             L1 = L1 -> next;
22         }
23         // L2所指向節點的exp大於L1所指向節點的exp
24         else if (L1 -> exp < L2 -> exp) {
25             q -> coef = L2 -> coef;
26             q -> exp = L2 -> exp;
27             p = p -> next = q;
28             L2 = L2 -> next;
29         }
30         // L2所指向節點的exp等於L1所指向節點的exp
31         else {
32             q -> coef = L1 -> coef + L2 -> coef;
33             q -> exp = L1 -> exp;
34 
35             // 係數求和後為0,不需要插入,同時把申請的節點釋放掉
36             if (q -> coef == 0) delete q;
37             // 係數不為零就要插入
38             else p = p -> next = q;
39 
40             L1 = L1 -> next;
41             L2 = L2 -> next;
42         }
43     }
44 
45     // 找到不為空的那個多項式
46     LNode *L = L1 ? L1 : L2;
47     // 把不為空的多項式剩餘的節點都接到求和連結串列的後面
48     while (L) {
49         p = p -> next = L;
50         L = L -> next;
51     }
52 
53     return head;
54 }
polyAdd

  由於連結串列帶有頭節點,所以先讓指標後移一個單位,指向第一個存放資料的節點。

  然後我們需要建立一個連結串列,用來儲存兩個多項式相加後的結果。

  之後我們進入迴圈,來進行多項式的相加,迴圈的條件是兩個多項式都存在,不為空。

  由於題目的要求是按指數遞降方式輸出,所以我們按下面的判斷規則來把相加的結果插入到新的連結串列中。

  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函式。

詳解線性結構 —— 一元多項式的乘法與加法運算
 1 LNode* polyMult(LNode *L1, LNode *L2) {
 2     // 讓指標後移一個單位,指向第一個存放資料的節點
 3     L1 = L1 -> next;
 4     L2 = L2 -> next;
 5 
 6     //  建立一個求積連結串列
 7     LNode *head = new LNode;
 8     head -> next = NULL;
 9 
10     while (L1) {
11         // 由於在內層迴圈中L2指標會改變,需要用headOfL2來儲存第二個多項式連結串列的首地址
12         LNode *headOfL2 = L2;
13 
14         while (L2) {
15             LNode *p = new LNode;
16             p -> next = NULL;
17             // 新節點存放多項式相乘的結果
18             p -> coef = L1 -> coef * L2 -> coef;
19             p -> exp = L1 -> exp + L2 -> exp;
20 
21             // 從頭開始遍歷求積連結串列,找到指數比新節點小的那個節點,返回那個節點的前一個節點的地址
22             LNode *pre = head;
23             while (pre -> next && pre -> next -> exp > p -> exp) {
24                 pre = pre -> next;
25             }
26             //  pre -> next == NULL或者pre -> next -> exp < p -> exp,直接插入就可以了
27             if (pre -> next == NULL || pre -> next -> exp < p -> exp) {
28                 p -> next = pre -> next;
29                 pre -> next = p;
30             }
31             //  pre -> next -> exp == p -> exp,不需要插入新節點,要判斷是否需要刪除求積連結串列中指數相同的那個節點
32             else {
33                 // 指數相同的兩個節點進行係數相加
34                 pre -> next -> coef += p -> coef;
35                 // 如果係數為零,就要刪除那個節點
36                 if (pre -> next -> coef == 0) {
37                     LNode *temp = pre -> next;
38                     pre -> next = temp -> next;
39                     delete temp;
40                 }
41                 // 無論怎麼樣都不需要把新節點插入,把它釋放放
42                 delete p;
43             }
44 
45             L2 = L2 -> next;
46         }
47 
48         // 讓L2重新指向第二個多項式連結串列的表頭
49         L2 = headOfL2;
50         L1 = L1 -> next;
51     }
52 
53     return head;
54 }
polyMult

  我們通過逐項相乘的方法來實現兩個多項式的求和。比如說,對於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函式。

詳解線性結構 —— 一元多項式的乘法與加法運算
 1 void printList(LNode *L) {
 2     // 這個if語句的作用是,如果傳入的多項式為空,為了讓它也有東西可以輸出,我們應該為他加入0,0這個項
 3     if (L -> next == NULL) {
 4         LNode *p = new LNode;
 5         p -> next = NULL;
 6         p -> coef = p -> exp = 0;
 7         L -> next = p;
 8     }
 9 
10     L = L -> next;
11     while (L) {
12         printf("%d %d", L -> coef, L -> exp);
13         if (L -> next) putchar(' ');
14         else putchar('\n');
15 
16         L = L -> next;
17     }
18 }
printList

  好了到此為止,我們已經把一元多項式的乘法與加法運算這個問題解決了,下面給出完整的程式碼。

 

完整程式碼

  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函式稍微改寫就可以了。

 1 LNode* creatList() {
 2     int n;
 3     scanf("%d", &n);
 4 
 5     LNode *head = new LNode;
 6     head -> next = NULL;
 7 
 8     while (n--) {
 9         LNode *p = new LNode;
10         p -> next = NULL;
11         scanf("%d %d", &p -> coef, &p -> exp);
12 
13         LNode *pre = head;
14         while (pre -> next && pre -> next -> exp > p -> exp) {
15             pre = pre -> next;
16         }
17         p -> next = pre -> next;
18         pre -> next = p;
19     }
20 
21     return head;
22 }

  有沒有發現,插入的過程和上面多項式求積後插入很像,其實他們的原理是一樣的。這樣子,我們就不需要按照指數遞降的順序來輸入,也可以實現指數遞降得順序輸出。

相關文章