【练习3.7】
编写一个函数将两个多项式相乘,用一个链表实现。你必须保证输出的多项式按幂次排列,并且任意幂次最多只有一项。
a.给出以O(M2N2)时间求解该问题的算法。
b.写一个以O(M2N)时间执行乘法的程序,其中M≤N。
c.写一个以O(MNlog(MN))时间执行乘法的程序。
d.上面哪个时间界最好?
Answer:
【a】.将两链表元素两两相乘并列出,从第一项开始,依次与其后的所有项比较,如相等则合并。
合并完成后,每次找出幂次最小的项,插入链表。(最原始的方法)
【b】.M≤1时,方法易知。
M≥2时,每次将长度为M的链表的一项,与另一链表的所有项相乘,每次一组N个有序的多项式元素。
对于每两组上式的N个多项式元素,基本按练习3.5有序链表求并的算法(除幂次相同需将系数相加)操作。
求并算法时间复杂度O(M+N),故该算法复杂度为
(乘法时间)O(MN)+(求并时间)O((N+N)+(2N+N)+(3N+N)+……+(MN+N))=O(M2N)
【详情见代码】
【c】.同a先将两链表元素两两相乘并列出,对MN项元素进行O(NlogN)的排序
排序完成后,遍历代码,合并同幂次项,最后全部插入链表。时间复杂度为:
(乘法时间)O(MN)+(排序时间)O(MNlogMN)+(合并同类项时间)O(MN)=O(MNlogMN)
【详见代码】
代码部分,首先是测试代码,b和c的测试代码写在一起了

1 #include <iostream> 2 #include "linklist.h" 3 using linklist::List; 4 using namespace std; 5 int main(void) 6 { 7 //测试多项式加法 8 List<Poly> a; 9 a.additem(Poly(3, 1)); 10 a.additem(Poly(1, 2)); 11 a.additem(Poly(4, 3)); 12 a.additem(Poly(7, 4)); 13 a.additem(Poly(2, 5)); 14 cout << " ( " << flush; 15 a.traverse(); 16 cout << ") + " << flush; 17 List<Poly> b; 18 b.additem(Poly(5, 2)); 19 b.additem(Poly(2, 3)); 20 b.additem(Poly(1, 5)); 21 b.additem(Poly(3, 7)); 22 b.additem(Poly(1, 11)); 23 cout << " ( " << flush; 24 b.traverse(); 25 cout << ") = " << flush; 26 27 List<Poly> answer = linklist::polymulti_seq(a, b); 28 List<Poly> another = linklist::polymulti_sort(a, b); 29 cout << " ( " << flush; 30 answer.traverse(); 31 cout << ") " << flush; 32 33 cout << " ( " << flush; 34 another.traverse(); 35 cout << ") " << flush; 36 system("pause"); 37 }
实现部分,首先需在poly.h中重载多项式元素的乘法运算符
1 //练习3.7新增,多项式元素乘法* 2 Poly operator*(const Poly& poly1, const Poly& poly2) 3 { 4 Poly answer; 5 answer.coefficient = poly1.coefficient*poly2.coefficient; 6 answer.exponent = poly1.exponent + poly2.exponent; 7 return answer; 8 }
然后是小题b代码,包括习题3.5求并成员函数的模板特例化的辅助函数及主相乘算法
1 //练习3.7b新增,将3.5求并的成员函数特例化 2 template <> void List<Poly>::join(List<Poly> inorder) 3 { 4 Node<Poly>* curr = front; 5 Node<Poly>* prev = nullptr; 6 Node<Poly>* curr2 = inorder.front; 7 while (curr != nullptr && curr2 != nullptr) 8 { 9 if (curr->data < curr2->data) 10 { 11 prev = curr; 12 curr = curr->next; 13 } 14 else if (curr2->data < curr->data) 15 { 16 additem(curr2->data, prev); 17 if (prev == nullptr) 18 prev = front; 19 else 20 prev = prev->next; 21 curr2 = curr2->next; 22 } 23 else 24 { 25 //对比3.5唯一增加语句 26 //当两元素幂次相等时,原链表与新链表的多项式系数相加并将指针后移 27 curr->data = curr->data + curr2->data; 28 prev = curr; 29 curr = curr->next; 30 curr2 = curr2->next; 31 } 32 } 33 while (curr2 != nullptr) 34 { 35 additem(curr2->data, prev); 36 if (prev == nullptr) 37 prev = front; 38 else 39 prev = prev->next; 40 curr2 = curr2->next; 41 } 42 } 43 44 //练习3.7b新增,以O(M²N)时间执行多项式乘法 45 List<Poly> polymulti_seq(const List<Poly> &inorder_a, const List<Poly> &inorder_b) 46 { 47 //保证首链表长度较小 48 if (inorder_a.size() > inorder_b.size()) 49 return polymulti_seq(inorder_b, inorder_a); 50 else 51 { 52 List<Poly> answer; 53 for (Node<Poly>* iter_a = inorder_a.begin(); iter_a != nullptr; iter_a = iter_a->next) 54 { 55 //用较短链表中每一个元素乘较长链表,得到临时链表 56 { 57 List<Poly> temp; 58 for (Node<Poly>* iter_b = inorder_b.begin(); iter_b != nullptr; iter_b = iter_b->next) 59 temp.additem(iter_a->data * iter_b->data); 60 answer.join(temp); 61 } 62 } 63 return answer; 64 } 65 }
然后为c小题算法,调用了标准库中的快排,需要#include<algorithm>
1 //练习3.7c新增,以O(MNlogMN)时间执行多项式乘法 2 List<Poly> polymulti_sort(const List<Poly> &inorder_a, const List<Poly> &inorder_b) 3 { 4 unsigned maxsize = inorder_a.size() * inorder_b.size(); 5 //申请M*N大小的数组 6 Poly* temp_array = new Poly[maxsize]; 7 unsigned int index = 0; 8 //依次对链表每两个节点元素相乘并放在数组中 9 for (Node<Poly>* iter_a = inorder_a.begin(); iter_a != nullptr; iter_a = iter_a->next) 10 for (Node<Poly>* iter_b = inorder_b.begin(); iter_b != nullptr; iter_b = iter_b->next) 11 temp_array[index++] = iter_a->data*iter_b->data; 12 //对数组进行升序快排 13 sort(&temp_array[0], &temp_array[--index]); 14 List<Poly> answer; 15 //单次遍历数组,合并同类项 16 for (index = 1; index < maxsize; ++index) 17 { 18 if (temp_array[index] == temp_array[index - 1]) 19 temp_array[index] = temp_array[index - 1] + temp_array[index]; 20 else 21 answer.additem(temp_array[index - 1]); 22 } 23 answer.additem(temp_array[index - 1]); 24 delete[] temp_array; 25 return answer; 26 }