数据结构上机报告实现一元多项式抽象数据类型.docx
《数据结构上机报告实现一元多项式抽象数据类型.docx》由会员分享,可在线阅读,更多相关《数据结构上机报告实现一元多项式抽象数据类型.docx(19页珍藏版)》请在冰豆网上搜索。
数据结构上机报告实现一元多项式抽象数据类型
数据结构
上机实习报告
第一次上机实习题目
实现一元多项式抽象数据类型
班级:
121141
姓名:
王庆涛
学号:
20141002513
指导老师:
郭艳
完成日期:
2016.04.21
1、需求分析
1.1问题描述和规格说明
已知一元n次多项式:
设计程序实现一元n次多项式的抽象数据类型,模拟一元n次多项式的操作行为。
包括:
数据元素:
ai,
存储结构,
逻辑操作:
1、构造一个空的多项式
2、多项式插入新的一项
3、多项式合并同类项
4、多项式的加法Pn(x)+Qn(x)=Rt(x)
5、多项式的乘法Pn(x)*Qn(x)=Rt(x)
6、打印多项式
7、计算多项式的值
1.2功能需求
1)首先构造两三个多项式供用户使用;
2)用户可以进行添加多项式或是添加多项式中的项;
3)或是修改其中的项,或是对多项式进行删除,或仅仅删除其中的某项;
4)或是查看当前的某项多项式
5)用户赋予多项式变量x值后可以计算多项式的值
6)可以计算两个或是多个多项式的和;
7)可以计算两个以上多项式的乘积
8)可以对多项式中的同类项进行合并
2、设计(目标:
有效组织与处理数据)
2.1抽象数据类型:
因为每个多项式有n个项,每个项包含不同的系数和指数,
多项式的系数ai抽象为整数,变量x也是整数,x的次幂n也是整数,故多项式的每一项抽象为一个Nape类型的节点,包括:
ai、x、n数据元素,最后整个一元n次多项式抽象为Polynomial数据类型。
详细设计如下:
Nope类型设计为:
classNope
{
friendclassPolynomial;//设置Polynomial为Nope的友元类,方便Polynomial类访问Nope的私有数据成员
private:
intm_factor;//项系数
intm_times;//次幂
public:
Nope(intfactor=0,inttimes=0);//构造函数
~Nope();
intGetFoctor()const;//获取项系数
intGetTimes()const;//获取次幂
voidSetFactor(intfactor);//设置项系数
voidSetTimes(inttimes);//设置次幂
Nope&operator=(constNope&item);//赋值=
intoperator<=(constNope&item);//比较<=//比较次幂的大小
friendostream&operator<<(ostream&out,constNope&item);//输出<<
Nope(constNope&item);//复制构造&
};
Polynoomial数据类型设计为:
classPolynomial
{
private:
intm_x;//多项式中的变量x
intm_size;//多项式的项数
LinListWithRearm_list;//存储多项式的带尾指针的单向链表
public:
Polynomial(intsize=0,intfactor=1);//可以构造系数为factor,个数为size的多项式,次幂依次增长
~Polynomial();
Polynomial(constPolynomial&poly);
intGetM_size()const;//获取多项式的项数
intGetM_x()const;
intGetM_factor(constint&index)const;//获取第index项的系数//从第1项开始(而不是第0项)
intGetM_times(constint&index)const;//获取第index项的次幂
inlinedoubleGetM_Number(constint&index)const;//获取第index项的值,因为计算多项式的值时频繁调用,所以设计为内联函数
intGetfactor(constint×)const;//获取次幂为times的项的系数//失败或没有,返回0
intGetIndex(constint×)const;//获取次幂为times的项的下标//从1开始
doubleGetNumber(constint×)const;//获取次幂为times的项的值//失败或没有返回0
doubleGetTotalNumber()const;//获取整个多项式的值
intSetM_factor(constint&index,constint&factor);//设置第index项的系数//从第1项开始(而不是第0项)
intSetfactor(constint×,constint&factor);//设置次幂为times的项的系数//失败返回0
intSetM_times(constint&index,constint×);//设置次幂为times的项的系数//失败返回0
intSetM_x(constint&x);//给未知数m_x赋值
boolDeleteIndex(constint&index);//删除第index项
boolDeleteTimes(constint×);//删除次幂为times的项
boolDeleteFactor(constint&factor);//删除所有系数为factor的项
inlineintInsertEnd(constint&factor,constint×);//从尾部插入新项,系数为factor,次数为times//失败返回0
inlinevoidInsertEnd(constNope&item);
Polynomial&operator=(constPolynomial&Poly);//赋值
voidCombine();//合并同类项且按次幂排序
voidPrint()const;//打印多项式
voidOrderPolynomial();//按次幂排序多项式
intOrderInsert(constint&factor,constint×);//有序插入新项,系数为factor,次数为times//失败返回0
Polynomialoperator+(constPolynomial&polyb);//多项式的加法
Polynomialoperator*(constPolynomial&polyb);//多项式的乘法
friendostream&operator<<(ostream&out,constPolynomial&item);//输出<<
};
2.2存储结构设计:
1)存储结构的确定
数据结构的目的是有效组织和处理数据。
为了有效组织和处理数据,先要分析一元n次多项式逻辑操作的特点和指针所占空间比例,然后确定最优的存储结构。
a)确定采用链式存储结构
1.n次多项式在构造时频繁执行插入操作,在程序运行阶段频繁执行删除或修改操作,且多项式的项数n不能确定,用户对项数n的需求变化大。
2.如果采用链表,指针存储开销和整个结点内容所占空间相比,其比例较小
综上所述,认为不采用顺序表,而采用链表。
b)选择哪种链式存储结构?
1.多项式在构造时可能经常在尾部插入或是在尾部修改数据,因此增设尾指针,尾指针始终指向链表的尾部结点。
通过增设尾指针,在表尾插入的算法时间复杂度为O
(1)。
综上所述,采用带尾指针的链表存储结构。
2)设计带尾指针的单链表
a)结构描述
b)逻辑操作
设带尾指针的循环单链表类型名为ListCWithRear,L是ListCWithRear型。
通过分析n次多项式的抽象数据类型,进一步确定带尾指针的单链表的逻辑操作如下所示:
1.LinListCWithRear(L)//初始化
2.IsEmpty(L)//判断是否是空表。
如果表为空,返回0,否则返回1。
3.InsertEnd(L,x)//在表尾插入新结点x。
插入成功返回1,失败返回0。
5.~LinListCWithRear(L)//撤销单链表
6.voidOrderInsert(constT&x);//单链表的有序插入
7.intSetItem(constT&item,constint&pos);//修改第pos个节点的数据
8.voidOrderList();//单链表内元素按<=符合排序
2.3算法设计
voidLinListWithRear:
:
OrderInsert(constT&x)//有序插入数据元素x
{
ListNode*curr,*pre;
curr=head->next;//curr指向首元结点
pre=head;//pre指向头结点
while(curr!
=NULL&&curr->data<=x)/*<=比较符*///定位插入位置
{
pre=curr;
curr=curr->next;
}
ListNode*q=newListNode(x,pre->next);//申请一个结点并赋值
pre->next=q;//把新结点插入在pre所指结点后
if(curr==NULL)rear=q;//尾指针始终指向链尾
size++;//表长加1
}
/*算法时间复杂度分析:
很明显,这个函数基本语句的执行次数是f(n)=n,
故时间复杂度T(n)=O(n);*/
voidLinListWithRear:
:
OrderList()
{
ListNode*curr=head;//curr指向头结点
while(curr->next!
=NULL)//<=比较符
{
ListNode*second=curr->next;//指向下一个节点
while(second->next!
=NULL)//<=比较符
{
ListNode*third=second->next;//指向下一个节点
if(curr->next->data<=third->data)//继续往下搜索
{
second=second->next;
}
else//third掉链,接在curr后面
{
second->next=second->next->next;
third->next=curr->next;
curr->next=third;
}
}
curr=curr->next;
}
rear=curr;
}
/*算法时间复杂度分析:
很明显,这个函数基本语句的执行次数是f()=n+n-1+n-2+....+2+1=(n-1)*n/2,
故时间复杂度T(n)=O(n*n);*/
Polynomial类:
PolynomialPolynomial:
:
operator+(constPolynomial&polyb)//多项式加法//
{
Polynomialpolyc;//局部变量,用于存储相加的结果
if(m_size+polyb.m_size==0)returnpolyc;
ListNode*pa=m_list.head;//获取第一个节点//pa指向头指针
ListNode*pb=polyb.m_list.head;
while(pa->Next()!
=NULL)
{
polyc.InsertEnd(pa->Next()->Data().m_factor,pa->Next()->Data().m_times);//从尾部插入
pa=pa->Next();//pa指向La的下一个元素
}while(pb->Next()!
=NULL)
{
polyc.InsertEnd(pb->Next()->Data().m_factor,pb->Next()->Data().m_times);
pb=pb->Next();//pb指向Lb的下一个元素
}
polyc.Combine();//合并同类项
returnpolyc;//返回相加结果
}/*算法时间复杂度分析:
很明显,这个函数基本语句的执行次数是f()=n+n=2n,
故时间复杂度T(n)=O(n);
*/PolynomialPolynomial:
:
operator*(constPolynomial&polyb)//多项式乘法
{
if(m_size==0||polyb.m_size==0)return*this;
Combine();//先将当前多项式合并同类项以减少乘法时间复杂度
Polynomialpolyc;
ListNode*pa=m_list.head;//获取第一个节点//pa指向头指针
ListNode*pb=polyb.m_list.head;
while(pa->Next()!
=NULL)
{
Nopetempa(pa->Next()->Data());
while(pb->Next()!
=NULL)
{
Nopetempb(pb->Next()->Data());
polyc.InsertEnd(tempa.m_factor*tempb.m_factor,tempa.m_times+tempb.m_times);
pb=pb->Next();//pb指向Lb的下一个元素
}
pa=pa->Next();//pa指向La的下一个元素
}
polyc.Combine();//将相乘结果合并同类项再返回
returnpolyc;
}/*算法时间复杂度分析:
很明显,这个函数基本语句的执行次数是f()=n+n+n+n+....+n+n=n*n,
故时间复杂度T(n)=O(n*n);
如果考虑InsertEnd(i);函数的执行次数也为T(n)=O
(1),
即时间复杂度仍然为T(n)=O(n*n);
*/voidPolynomial:
:
Combine()//合并同类项且
{
ListNode*pa=m_list.Index
(1);//获取第一个数据节点
intindex1=0;
while(pa->Next()!
=NULL)
{
index1++;
intindex2=0;
ListNode*pb=pa;
Nopetempa(pa->Data());
while(pb->Next()!
=NULL)
{
index2++;
Nopetempb(pb->Next()->Data());
if(tempa.m_times==tempb.m_times)
{
tempa.SetFactor(tempa.m_factor+tempb.m_factor);
pa->SetData(tempa);
//pb=pb->Next()->Next();
m_list.Delete(index1+index2);
m_size--;
index2--;//删除一个
}
elsepb=pb->Next();//pb指向Lb的下一个元素
}
pa=pa->Next();//pa指向La的下一个元素
}
}
/*算法时间复杂度分析:
很明显,这个函数基本语句的执行次数是f(n)=n+n-1+n-2+.....+1=(n+1)*n/2,
故时间复杂度T(n)=O(n的2次方);*/
2.4模块及调用关系
文件包含关系
调试类结构:
多项式类结构:
3、使用说明
1.本程序运行在windows系列的操作系统下,执行文件为:
ADTPolynomial.exe。
2.用户需严格按照用户界面的输入提示说明输入数据进行测试使用。
3.在使用中输入的选择项数请从第一项开始算起,而不是第零项。
除非界面提示可以输入;否则可能引起访问越界导致程序退出!
4.输出结果表示多项式的当前结构,格式为
Pn(x)=a*pow(x,y1)+b*pow(x,y2)+……..
Pow(x,y)表示x的y次方,a,b表示项的项数
5.只有当给多项式的变量x赋值之后才可以求出多项式的总值,否则求值为0;
4、调试分析
1.在看课本时我一直以为链表的head指针是另外一个单独的指针,head->next是头节点,head->next->next才是首元节点,所以写代码时出现了很多的错误,调试过程中才发现head是头指针,head->next就是首元节点,才算深刻认识了链表啊
2.在测试类中我是用一个vector来装需要测试的多项式的,但是编译器却报错说我没有写构造函数//errorC2558:
class'Polynomial':
nocopyconstructoravailable
解决方法:
为Polynomial类写默认的构造函数之外还要写一个复制构造函数。
否则多项式对象不能进行复制传值
3.多项式类要进行频繁的删除项、添加项、相加、相乘、合并同类项这些操作,如果仅仅使用带尾指针的链表的公有接口的话,一个简单的操作就要对链表进行相当大的重复操作,时间效率相当低下
解决方法:
把多项式类polynomial类设计为链表类LinList的友元类,这样可以通过Polynomial类直接对链表结构操作,用好算法编写高效率的程序,提高时间效率。
5、测试数据
测试实例:
运行ADTPolynomial.exe结果如下:
1.添加多项式或是添加项
2.删除多项式或是删除项
3.打印多项式
4.多项式加法
5.多项式乘法多项式合并同类项
6.计算多项式的值
6、心得体会
这是我第一次以对数据的结构进行操作而实现编程功能的一次练习,以往我都是直接使用数组或是容器来存储数据,没有学习数据结构之前还不知道有其他什么数据结构来装载数据以为数组和容器vector就是万能的了,但是当我学习了数据结构之后我才发现不能所有的数据都用同一种容器装载,不能所有的问题都用同一种方法来解决,在编程的世界里要学会运用不同的方法解决问题,要使用最高效、最经济的方法,才是最好的方法。
通过这次上机练习,我也更加深刻的认识到知识不能仅仅在书中取得,更要在实践中检验,那样才能对知识有深入的理解,并且实践能更好的辅助我们理解书本知识(就像我曾经理解head指针一样)。
第一次比较正规地涉足数据结构的领域,发现数据结构的世界是如此的精彩,如此的诱人,如此饱含活力,相信我能越学越精!