双向链表实现两个多项式的加法与乘法
#include <iostream>
using namespace std;
template<typename E>
class Link { //声明Link类,用于存放多项式的一项;
private:
static Link<E>* freelist; //创建静态全局变量freelist用于指向可利用空间表的头结点;
public:
Link * prev;
E element1;
E element2;
Link * next;
Link(Link *p = NULL, Link *n = NULL) {
prev = p;
next = n;
element1 = NULL;
element2 = NULL;
}
Link(const E& e1, const E& e2, Link *p = NULL, Link *n = NULL) {
element1 = e1;
element2 = e2;
prev = p;
next = n;
}
~Link() { }
void operator delete(void *ptr) { //重载Link类的delete操作符(注意叫delete操作符,不叫delete函数);
((Link<E>*)ptr)->next = freelist;
freelist->prev=
freelist = (Link<E>*)ptr;
}
void * operator new(size_t) { //重载Link类的new操作符(注意叫new操作符,不叫new函数);
if (freelist == NULL) return ::new Link;
Link<E>* temp = freelist;
freelist = freelist->next;
return temp;
}
};
template<typename E>
Link<E>* Link<E>::freelist = NULL; //将freelist赋值为空值;
template <typename E>class doublelist { //声明doublelist类,一个双向链表,用于存放多项式;
public:
Link<E>* head;
Link<E>* tail;
Link<E>* curr;
void init() { //初始化成员私有函数,在调用构造函数时使用;
head = new Link<E>;
curr = head;
tail = new Link<E>;
head->next = tail;
tail->prev = head;
curr = head;
}
public:
doublelist()
{
init();
}
int get_cnt() { //获取存放于doublelist里的多项式的项数;
int xiangshu = 0;
for (curr = head->next; curr != NULL; curr = curr->next) {
if ((curr->element1) != 0) xiangshu++;
}
return xiangshu;
}
~doublelist(){}
void removeall() //将双向链表清空的函数,但是头结点和尾结点任然保留着的;
{
while (head->next != tail)
{
Link<E> * temp = head->next;
head->next = head->next->next;
head->next->prev = head;
delete temp;
}
}
void append(const E &xishu, const E & zhishu) { //向双向链表的尾部(tail指针的前一个位置,及在tail前,并不是在当前的tail后)添加Link节点;
tail->prev = tail->prev->next = new Link<E>(xishu, zhishu, tail->prev, tail);
}
void operator=(doublelist &D) //重载赋值运算符
{
this->removeall();
D.curr = D.head->next;
while (D.curr != D.tail)
{
this->append(D.curr->element1, D.curr->element2);
D.curr = D.curr->next;
}
D.curr = D.head->next;
}
friend ostream & operator << (ostream & os, doublelist ot) { //重载输出运算符,使输出符合实验要求
int xiangshu = 0;
for (ot.curr = ot.head->next; ot.curr != NULL; ot.curr = ot.curr->next) { //此循环获得项数
if ((ot.curr->element1) != 0) xiangshu++;
}
os << xiangshu << endl;
for (ot.curr = ot.head->next; ot.curr->next != NULL; ot.curr = ot.curr->next) { //此循环输出多项式的每一项,每一项的系数和指数用一个空格隔开
//if((ot.curr->element1)!=0)
os << ot.curr->element1 << ' ' << ot.curr->element2 << endl;
}
/*ot.curr = ot.head->next;
while (ot.curr->next!=NULL) {
os << ot.curr->element1 << " " << ot.curr->element2 << endl;
ot.curr = ot.curr->next;
}
ot.curr = ot.head;*/
return os;
}
};
void add(doublelist<int> list1, doublelist<int> list2, doublelist<int> & temp) //将两个多项式相加的函数
{
doublelist<int> addresult;
list1.curr = list1.head->next; //将list1的curr指向多项式的第一项,以便后面的循环。注意:多项式的第一项在head->next中,head并没有存放多项式的项;
list2.curr = list2.head->next; //将list2的curr指向多项式的第一项,以便后面的循环。注意:多项式的第一项在head->next中,head并没有存放多项式的项;
while (1)
{
if (list1.curr->element2 > list2.curr->element2) //如果list1的当前项的指数大于list2的当前项的指数,就把list1的当前项添加到addresult里;
{
addresult.append(list1.curr->element1, list1.curr->element2);
list1.curr = list1.curr->next;
}
else
{
if (list1.curr->element2 < list2.curr->element2) //如果list1的当前项的指数小于list2的当前项的指数,就把list2的当前项添加到addresult里;
{
addresult.append(list2.curr->element1, list2.curr->element2);
list2.curr = list2.curr->next;
//cout << "2" << endl;
}
else
{
if ((list1.curr->element2 == list2.curr->element2) && (list1.curr != list1.tail && list2.curr != list2.tail)) //如果list1的当前项的指数等于list2的当前项的指数,就把list1和list2相加;并且要保证都不在尾结点,在尾结点下面的语句处理
{
addresult.append(list1.curr->element1 + list2.curr->element1, list2.curr->element2);
list1.curr = list1.curr->next;
list2.curr = list2.curr->next;
}
else
{
if (list1.curr == list1.tail) //list1.curr在尾结点,
{
addresult.append(list2.curr->element1, list2.curr->element2);
list2.curr = list2.curr->next;
}
else
{
if (list2.curr == list2.tail) //list2.curr在尾结点
{
addresult.append(list1.curr->element1, list1.curr->element2);
list1.curr = list1.curr->next;
}
}
}
}
}
if ((list1.curr == list1.tail) && (list2.curr == list2.tail)) break;
}
list1.curr = list1.head;
list2.curr = list2.head;
temp = addresult;
}
void multi(doublelist<int> list1, doublelist<int> list2, doublelist<int>& multiresult) { //将两个多项式相乘的函数
//cout << list2;
int list1_xiangshu = list1.get_cnt();
int list2_xiangshu = list2.get_cnt();
list1.curr = list1.head->next;
list2.curr = list2.head->next;
for (int i = 0; i < list1_xiangshu; i++)
{
doublelist<int> tempmultiresult;
int list1_xishu1 = list1.curr->element1;
int list1_xishu2 = list1.curr->element2;
list2.curr = list2.head->next; //在开始时一定要移到第一项
for (int j = 0; j < list2_xiangshu; j++)
{
int list2_xishu1 = list2.curr->element1;
int list2_xishu2 = list2.curr->element2;
tempmultiresult.append(list1_xishu1 * list2_xishu1, list1_xishu2 + list2_xishu2);
list2.curr = list2.curr->next;
}
add(tempmultiresult, multiresult, multiresult);
list1.curr = list1.curr->next;
}
}
int main() {
ios::sync_with_stdio(false);
cout.tie(NULL);
doublelist<int> list1, list2, addresult, multiresult;
int fxiangshu, sxiangshu;
cin >> fxiangshu >> sxiangshu;
for (int i = 0; i < fxiangshu; i++)
{
int tempxishu, tempzhishu;
cin >> tempxishu >> tempzhishu;
list1.append(tempxishu, tempzhishu);
}
for (int i = 0; i < sxiangshu; i++)
{
int tempxishu, tempzhishu;
cin >> tempxishu >> tempzhishu;
list2.append(tempxishu, tempzhishu);
}
add(list1, list2, addresult);
cout << addresult;
multi(list1, list2, multiresult);
cout << multiresult;
return 0;
}
1.项目分析
本次实验的任务为用双向链表进行两个一元多项式的加法和乘法。双向链表的逻辑特征可以描述为“利用节点本身的特点将节点连接起来,并且每个节点不仅存放了下一个节点的地址,同时也存放了上一个节点的信息。”双向链表的优点就在于不仅可以通过当前的节点访问当前节点的下一个节点,而且还可以通过当前节点访问其上一个节点的内容。将双向链表用于本次项目,将每个多项式的信息存放于双向链表中,然后对双向链表进行操作,并最终得到结果。
2.算法设计
(1) 对于两个多项式的加法,先创建一个双向链表addresult用于存放和的结果。将第一个多项式list1的每一项(从list1,list2的head节点开始)与第二个多项式list2的每一项比较。将指数大的那一项添加到addreuslt里面去;如果两个项的指数相等,那就现将这两个项相加再存放于addresult里面(系数相加,指数不变)。按照这样的步骤进行到list1和list2的curr指针都指向自身的尾结点tail。得到的最终addresult即是已经排好序的(按指数从大到小排序)的和多项式了。
(2) 对于两个变量的乘法,将list1的每一项和list2的每一项相乘(先固定list1.curr指向多项式的第一项,将这一项与list2的每一项相乘,将得到的结果与multiresult相加,然后将相加的结果再复制给multiresult,将list1的curr指针指向其下一个节点,通过这两层循环遍历所有项,最终得到的结果即是两个多项式相乘的结果)。此算法的复杂度度为O(n^2)。
3.关键代码描述
(1) 先创建一个节点类Link。这个类用来存放一个多项式的某一项的系数和指数,也就是一个节点包含多项式的一项的系数,指数,一个指向前一个节点的节点指针以及一个指向后一个节点的指针。同时,对节点的new操作符和delete函数进行重载(先创建一个空节点(取名为‘freelist’),并声明为静态全局变量),当每次delete操作符被调用时,就将被“删除”的这个节点和freelist连接起来,放在freelist的前面,形成一个可利用空间表;每次调用new操作符的时候,如果可利用空间表不是空的,就将freelist这个节点作为new操作符的返回节点,如果可利用空间表为空了,就调用标准的C++ new操作符。
(2) 基于Link类创建一个双链表类doublelist。双链表类的数据成员有三个Link类的变量(名字名为head,curr与tail,分别用来指向双向链表的头部节点,当前节点以及尾部节点)。
(3) 为了防止双向链表赋值时发生错误,重载双向链表的赋值运算符。想调用removeall()函数把被赋值的变量清空,然后执行循环,将变量D的每一项添加到被赋值的变量里,直到D的末尾为止。
(4) 重载”<<”运算符。为了使输出格式满足实验要求,重载了”<<”运算符。
先通过一个循环遍历双向链表的每一项,得到其项数,再通过一个循环输出每个Link的系数的值与指数的值,项数与系数的值的中间用一个空字符隔开。
4.系统测试报告
5.运行结果
6.总结
通过双向列表来存放每一个多项式,让后调用add()函数和multi()函数来实现多项式的加法和乘法。
本次算法的时间复杂度为n^2,如果采用“快速傅里叶变换”来实现两个多项式的乘法,算法的时间复杂度会降低到O(nlog(n))。