数据结构实验2 线性表的应用

背景

在数学上,一个一元n次多项式Pn(x)可按降序写成:
在这里插入图片描述

它是由n+1个系数唯一确定。因此,在计算机里它可以用一个线性表P来表示:

P=(Pn, Pn-1, …, P1, Po)一元多项式的运算包括加法、减法和乘法,而多项式的减法和乘法都 可以用加法来实现。

实验目的

线性表ADT的应用,基于线性表设计和实现两个一元多项式的加法运算。
提示:用有序线性表表示一元多项式。表内元素按照多项式的次数递减的次序排列。

基本要求

1.参考课程“线性表ADT的设计和表示”,定义、设计并实现一个有序线性表ADT。
2.需要利用链表来实现有序线性表。
3.需要基于有序线性表的基本操作来实现一元多项式的加法运算。

实验报告

一、 需求分析

0.问题描述

在数学上,一个一元n次多项式Pn(x)可按降序写成:
在这里插入图片描述

它是由n+1个系数唯一确定。两个多项式相加就是把它们的同次项的系数相加,给定两个多项式:
在这里插入图片描述
并且设m<=n,则多项式f(x)和g(x)的和指的是:
在这里插入图片描述

这里当m<n时,

现在给出两个多项式,请你求出这两个多项式的和。

1.问题分析

实现的功能:
1.分别通过键盘输入两个多项式的项数和每一项的指数和系数。
2.将两个多项式进行求和。
3.通过屏幕显示忽略0系数项的求和后的多项式。

2.输入数据

  1. 共输入两组数据,其中每组数据的第一行为项数m,接下来的m行中,每行第一个数为系数,第二个数为指数,数据之间用空格隔开。

  2. 系数采用整型int,指数采用整形int。

  3. 输入的每个多项式的指数保证各不相同,且以由大到小的顺序输入。

  4. 数据规模和用例:对于所有评测用例,保证每个多项式的项数0<m<20,且输入的系数满足double型,指数满足int型且不小于0。

3.输出数据

通过屏幕输出求和后的多项式,形式如,当某项系数为1时,输出忽略数字1;忽略系数为0的项。

4.测试样例设计

样例一:检验某项系数和为0的情况

3

2 4

1 2

3 1

4

1 4

-1 2

-2 1

3 0

输出:
在这里插入图片描述

样例二:检验所有系数和为0的情况

2

3 4

-1 1

2

-3 4

1 1

输出:0

样例三:检验每项指数都相同的情况

2

2 3

4 1

2

-1 3

6 1

输出:
在这里插入图片描述

样例四:检验每项指数都不同的情况

3

2 5

1 2

-4 1

3

5 4

2 3

3 0

输出:
在这里插入图片描述

样例五:检验含有常数项系数的情况

2

-3 4

1 0

3

2 5

1 3

3 0

输出:
在这里插入图片描述

二、 概要设计

0.数据类型

由于多项式的每一项都有指数和系数两个属性,因此这里可以定义一个二元组poly,其中系数(num)和指数(exp)是其数据成员。

1.抽象数据类型

数据对象:一元n次多项式的所有项
数据关系:每一项前后相继,具有一定的线性特征,为线性关系
基本操作:
1.准备能储存这组数据的储存空间
2.添加元素
3.访问元素
线性表ADT的设计:

      ADT  node{

                   数据对象:D={pi|pi∈ploy,i=1,2,... ,n,n∈整数}   
                   数据关系:R={<pi-1,pi>|pi-1,pi∈D}
                   基本操作:
                   void init();
                  //操作功能:初始化线性表,构造出一个空表
                  void Append(ploy &Elem);
                  //操作功能:将元素Elem添加到线性表的表尾
                  void next();
                  //操作功能:将当前位置移动到下一位置
                  poly& getvalue();
                  //操作功能:获取当前位置的元素值
                  void moveToStart();
                  //操作功能:将当前位置移动定位到表头
				  bool empty();
				  //操作功能:判断线性表是否为空,若为空返回真,否则返回假
	}

2.算法的基本思想

  1. 两个多项式用线性表A和B表示,每个多项式的项作为一个元素储存在线性表的一个位置中,每个元素都有系数和指数两个属性;
  2. 同时从A和B线性表表头的第一个元素开始比较其元素的指数;
  3. 如果A的指数大于B,则将A中的该项存到线性表C中,然后再比较B的当前项和A的后一项的指数;如果A的指数小于B,则将B的该项放入C中的,然后再比较A的当前项和B的后一项的指数;如果相等则将系数相加,系数不为0时,则将其系数与指数存入C中,然后同时比较A和B的后一项;
  4. 最后将A或B的剩余项存入C中;
  5. 遍历线性表C,将相加后多项式的各项输出。

3.程序的流程

共分为三个模块:输入模块、比较模块、输出模块

输入模块:初始化线性表A和B,调用添加函数,将通过键盘输入的系数和指数存储到A、B中。
比较模块:遍历A、B,合成新的系数,赋给线性表C的元素。
输出模块:遍历C,获取每个项的系数和指数,并通过屏幕输出。

三、详细设计

1.物理数据类型

物理数据类型:每个数据对象可以选用结构体这种数据类型,系数和指数为其数据成员。

物理数据结构:由于当相加后的多项式中存在大量的零系数时,采用顺序储存结构会浪费大量的储存空间,所以可采用链式储存结构来表示多项式,这里我们选用单向链表,多项式的每个系数非0的项作为一个数据对象储存在链表每个结点的数据域之中。

ADT的实现:

void init() // 链表初始化

{      

   current = tail = head = new link();

   length= 0;

 }

void next()//移动指针到下一位置

{

    if (current != tail) current = current->next;

	 else return; 

}

ploy& getvalue()  // 返回当前元素

{ 

   assert(current != NULL);//内容为空

   return current->elem;

 } 

void append(poly p)     // 在列表的尾部追加结点并赋值

{

   tail = tail->next = new Link(p, NULL);

   length++;

 }

int getlength() //返回线性表长度

{

    return length;

} 

bool empty();//判断链表是否为空

{

    if(length==0) return ture;

    return false;

}

//移动至链表开始位置

void moveToStart()
{ 
	current = head;
 }

2.输入和输出的格式

输入格式:
第一行:输入第一组数据的项数m;
接下来的m行:输入每一项的系数和指数,系数和指数之间用空格隔开;
第m+1行:输入第二组数据的项数n;
接下来的n行:输入每一项的系数和指数,系数和指数之间用空格隔开;

输出格式:将合并后的多项式在屏幕上显示。形式如

在这里插入图片描述

当某项系数为1时,输出忽略数字1;忽略系数为0的项。

3.算法的具体步骤

输入模块:

//申请两个链表list1和list2          list list1,list2; poly p;    
//输入多项式a的项数                 cout<<"请输入多项式A的项数n:";    
                                   int n;cin>>n;   
								   cout<<"请输入多项式A的系数和指数:  ";     
//输入多项式的系数和指数,,           for(int i=0;i<n;i++){
先将其储存到结构体对象p中             cin>>num>>index;    
,然后将p添加到链表1中               list1.Append(num,index);                                    
                                  }

//输入多项式b的项数                 cout<<"请输入多项式B的项数m:";   
                                  int m;cin>>m;
                                  cout<<"输入多项式B的系数和指数:”

//输入多项式的系数和指数            for(int i=0;i<m;i++){
,先将其储存到结构体p中,              cin>>num>>index;    
再将p添加到链表2的表尾                 List2.Append(num,index);                                        
								  }

比较模块:

//L1和L2储存已知多项式,         L3List add(L1,L2, L3)
储存相加后的多项式               {    
                                     poly pp;    
                                     int x1=L1.getlength(),x2=L2.getlength();    
//从头开始遍历L1和L2,         	     while(x1>0&&x2>0)    
当有其中的一个链表遍历结束             {    
时,循环结束                             if   (L1.getvalue().exp == L2.getvalue().exp)     
//当两个结点中元素指数相同时              {    
                                   		      if(L1.getvalue().num+L2.getvalue().num != 0)     
//对两项进行合并,相加后的系数        			    {  
不为0时,将该项储存到L3中                             pp.exp=L1.getvalue().exp;    
                                         		    pp.num=L1.getvalue().num+L2.getvalue().num;    
                               		                L3.append(pp);
                                      		     }
                                              L1.next();L2.next();x1--;x2--;}    
//由于给定的两个多项式都是降幂排列,			else if (L1.getvalue().exp > L2.getvalue().exp) 
所以两个链表的结点的指数大的项不需   			 {    
要合并                                                  pp.exp=L1.getvalue().exp;    
                                                       pp.num=L1.getvalue().num;    
                                                       L3.append(pp);    
                                                       L1.next();    
                                                       x1--;    
//将指数较大的项储存到链表L2的结点               }    
                                            else if(L1.getvalue().exp < L2.getvalue().exp)    
                                            {    
                                                        pp.exp=L2.getvalue().exp;    
                                                        pp.num=L2.getvalue().num;    
                                        		        L3.append(pp);    
                        		                        L2.next();    
                          			                    x2--;}}    
//链表当前位置每改变一次,
 长度x1,x2减少1           		    if (x1==0&&x2==0) return   L3;    
//x1=x2=0时两个链表同时遍历完        else if(x1>0)    
 返回L3                        	   {while(x1>0){    
                                             pp.exp=L1.getvalue().exp; 
//若x1>0,则L1没有遍历结束                     pp.num=L1.getvalue().num;    
将L1中剩下的结点的元素赋给    			     L3.append(pp);    
  L3                           		         L1.next();    
                                                x1--;
                                          }    
                                          return L3;}    
//若x1>0,则L1没有遍历结束        else if(x2>0){    
将L1中剩下的结点的元素赋给        while(x2>0){    
L3                                     pp.exp=L2.getvalue().exp;    
                                       pp.num=L2.getvalue().num;    
                                       L3.append(pp);    
                                       L2.next();    
                                        x2--;}    
                                 return L3;}    
                               } }

输出模块:

                               void print(list &L){
 //如果L为空,则两多项式         if(L.empty())  cout<<0;    
相加结果为0                	   else{    
                                         x=L.getlength(); 
                               		    while(x>0)   
 //否则,依次访问L中结点存储的元素        {
										   cout<<L.getvalue().num<<"x^"<<L.getvalue().exp;    
										    x--; }    
									 }
							   } 

4.算法的时空分析

输入模块:要一直从链表的尾部插入节点,所以时间复杂度是O(n)。

比较模块:要同时遍历两个链表并比较其元素指数,所以时间复杂度是O(n^2)。

输出模块:获取节点的值的时间代价为常数,但要遍历整个链表C,因此时间复杂度是O(n)。

四、测试结果

测试数据一:
在这里插入图片描述

分析:两个多项式同有指数为4和2的项,可进行合并

测试数据二:

在这里插入图片描述

分析:合并后系数都为0,因此最后输出为0

测试数据三:

在这里插入图片描述

测试数据四:

在这里插入图片描述

测试数据五:

在这里插入图片描述

五、实验日志(选做)

2018-10-25:

看了超星中老师的实验报告解读录像,编撰了预习报告

2018-10-28:

根据老师对预习报告的批语,对问题需求分析进行改动,完善了实验题目

2018-11-1:

继续改动实验报告,对ADT的设计进行修改,运用了二元组

2018-11-2:

根据实验报告编写了代码,发现遇到的错误全部来源于指针的指向

2018-11-3:

修改代码,进行调试分析,完善最终的实验报告

附:代码

**Link.h**
#include <iostream>
#ifndef _LINK_H_
#define _LINK_H_


typedef struct poly
{
	int num;
	int exp;
}poly;

class Link
{
	public:
		poly p; //结点值
		Link *next; //结点指针:在链表中指向下一结点
	//构造函数 
		Link(poly& elemval, Link* nextval =NULL)
  	 	{ p = elemval;  next = nextval; }

  		Link(Link*nextval = NULL) { next = nextval; }
		
};

#endif
**list.h**
#include <iostream>
#ifndef _LINK_H_
#define _LINK_H_
    
typedef struct poly
{
	int num;
	int exp;
}poly;

class Link
{
	public:
		poly p; //结点值
		Link *next; //结点指针:在链表中指向下一结点
		//构造函数 
		Link(poly& elemval, Link* nextval =NULL)
  	 	{ p = elemval;  next = nextval; }    
  		Link(Link*nextval = NULL) { next = nextval; }
		
};

#endif
**llist.h**
#include "Link.h"
#include "list.h"
#include<assert.h>

void list::init() // 链表初始化
{      
   curr = tail = head = new Link( );
   length = 0;
 }
void list::next()//移动指针到下一位置
{
	if (curr != tail)  curr = curr->next;
	else return; 
}
poly& list::getvalue( )  // 获取当前位置的元素值,赋值给Elem
{ 
   assert(curr != NULL);//内容为空
   return curr->p;
 } 
void list::insert(poly &P)     // 有序的插入结点 
{
   curr = head;
   int i=0;
   for (i=0; i<length; i++)
   {
   		if (P.exp > curr->next->p.exp)
   		{
   			curr->next = new Link(P,curr->next);
   			length++;
   			break;
		}
	curr = curr->next;
	} 
	if (i == length)
	{
		tail = tail->next = new Link(P, NULL);
  		length++;
	}
   
 }
void list::append(poly &P)
{
	tail = tail->next = new Link(P, NULL);
  	length++;
}
//移动至链表开始位置
void list::moveToStart(){ curr = head->next; }

int list::getlength() //返回线性表的长度 
{
	return length; 
} 

bool list::empty()
{
	if (length == 0) return true;
	return false;
 } 
**main**
#include <iostream>
#include "Link.h"
#include "list.h"
#include "llist.h"
using namespace std;

list add(list L1,list L2,list &L3);
void print(list L);

int main()
{
	list list1,list2,list3; poly p1; 
	cout<<"请输入多项式a的项数n:";
	int n; cin>>n;
	list1.init();
	cout<<"请对多项式a的系数和指数赋值,如: 2 4 3 1   "<<endl; 
	for(int i=0;i<n;i++)
	{
		cin>>p1.num>>p1.exp;
		list1.insert(p1);
    }
    
    cout<<"请输入多项式b的项数m:";
    int m; cin>>m;
    list2.init();
    cout<<"请对多项式b的系数和指数赋值,如: 2 4 3 1   "<<endl; 
	for(int i=0;i<m;i++)
	{
		cin>>p1.num>>p1.exp;
		list2.insert(p1);
    }
    list3.init();
    cout<<"请输出相加后的多项式,形如:2x^4+x^3-7x^2+1:"<<endl;
    add(list1,list2,list3);
    print(list3);
    
    return 0;
} 

list add(list L1,list L2,list &L3)
{
	L1.moveToStart();
	L2.moveToStart();
	
	poly pp;
	int x1=L1.getlength(),x2=L2.getlength();
	while(x1>0&&x2>0)
	{
		if (L1.getvalue().exp == L2.getvalue().exp) 
	{
		if (L1.getvalue().num+L2.getvalue().num != 0) 
		{
			pp.exp=L1.getvalue().exp;
			pp.num=L1.getvalue().num+L2.getvalue().num;
			L3.append(pp);
		}
		L1.next();L2.next();
		x1--;x2--;
	}
	else if (L1.getvalue().exp > L2.getvalue().exp) 
	{
			pp.exp=L1.getvalue().exp;
			pp.num=L1.getvalue().num;
			L3.append(pp);
			L1.next();
			x1--;
	}
	else if (L1.getvalue().exp < L2.getvalue().exp) 
	{
			pp.exp=L2.getvalue().exp;
			pp.num=L2.getvalue().num;
			L3.append(pp);
			L2.next();
			x2--;
	}
	
	}
	
	if (x1==0&&x2==0) return L3;
	else if(x1>0)
	{
		while(x1>0)
		{
			pp.exp=L1.getvalue().exp;
			pp.num=L1.getvalue().num;
			L3.append(pp);
			L1.next();
			x1--;
		}
		return L3;
	}
	else if(x2>0)
	{
		while(x2>0)
		{
			pp.exp=L2.getvalue().exp;
			pp.num=L2.getvalue().num;
			L3.append(pp);
			L2.next();
			x2--;
		}
		return L3;
	}
}




void print(list L)
{
	if(L.empty()) cout<<0;
	else{
		
	L.moveToStart();
	if (L.getvalue().num == 1)
		{
			if (L.getvalue().exp == 1) cout<<"x";
			else if (L.getvalue().exp > 1) cout<<"x^"<<L.getvalue().exp;
			else if(L.getvalue().exp == 0) cout<<1;
		} 
		else 
		{
			cout<<L.getvalue().num;
			if (L.getvalue().exp == 1) cout<<"x";
			else if (L.getvalue().exp > 1) cout<<"x^"<<L.getvalue().exp;
		}
	for (int i=1; i<L.getlength(); i++)
	{
		L.next();
		if (L.getvalue().num>0) 
		{
			cout<<"+";
			if (L.getvalue().num == 1)
			{
				if (L.getvalue().exp == 1) cout<<"x";
				else if (L.getvalue().exp > 1) cout<<"x^"<<L.getvalue().exp;
				else if(L.getvalue().exp == 0) cout<<1;
			} 
			else 
			{
				cout<<L.getvalue().num;
				if (L.getvalue().exp == 1) cout<<"x";
				else if (L.getvalue().exp > 1) cout<<"x^"<<L.getvalue().exp;
			}
		}
		else if (L.getvalue().num<0) 
		{
			if (L.getvalue().num == -1)
			{
				if (L.getvalue().exp == 1) cout<<"-x";
				else if (L.getvalue().exp > 1) cout<<"-x^"<<L.getvalue().exp;
				else cout<<-1;
			} 
			else 
			{
				if (L.getvalue().exp == 1) cout<<L.getvalue().num<<"x";
				else if (L.getvalue().exp > 1)cout<<L.getvalue().num<<"x^"<<L.getvalue().exp;
				else cout<<L.getvalue().num;
			}
		}
	}
	
    }
}
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实验一 线性表及其应用 一、 实验目的和要求 1、掌握线性表的插入、删除、查找等基本操作设计与实现 2、学习利用线性表提供的接口去求解实际问题 3、熟悉线性表的的存储方法 二、 实验内容和原理 1、实验内容:设计一个一元多项式的简单计算器,其基本功能有①输入并建立多项式;②输出多项式;③多项式相加。可利用单链表或单循环链表实现之。 2、实验原理:以线性表来描述一元多项式,存储结构采用单链表,每个结点存储的多项式中某一项的系数和指数,建立单链表指数高的结点列于指数低的 结点之后,即线性表的元素按指数递增有序排列。 三、 实验环境 Visual C++ 6.0 及PC机 四、 算法描述及实验步骤 思想算法: 以线性表来描述一元多项式,存储结构采用单链表,每个结点存储的多项式中某一项的系数和指数,建立单链表指数高的结点列于指数低的结点之后,即线性表的元素按指数递增有序排列。 例如构造两个多项式ha: 5X3+4X2+3X+2 hb: X2+X+1 多项式加法:定义指针p,q分别指向ha,hb i.p->exp==q->exp ,r->coef=p->coef+q->coef,pa,pb下移; ii.p->expexp ,r->coef=q->coef;r->exp=q->exp;,q下移 iii.pa->exp>pb->exp, r->exp=p->exp;r->coef=p->coef;,p下移 iv.p!=NULL,pb==NULL.相当于iii. V.q==NULL,pb!=NULL.相当于ii. 其流程图如下: 多项式乘法:定义指针fp,gp分别指向f,g 1.将两多项式最大指数相加并赋于maxp,并置g 2.用for循环求指数等于maxp时相乘的系数 3. (fp!=NULL)&&(gp!=NULL), p=fp->exp+gp->exp 1.p>maxp, fp=fp->next; 2. pnext; 3.p=maxp, x+=fp->coef*gp->coef; fp=fp->next;gp=gp->next; 五、 实验结果 1.分别输入两个多项式: 5X3+4X2+3X+2 和X2+X+1,然后输出结果如下: 2.分别输入两个多项式:6X4+4X2+2和5X+6,然后输出结果如下: 六、 总结 此次上机实验应用线性表实现了一次实际操作,完成了一个一元多项式的简单计算器,不仅对此次编译程序的算法思想有了新的认识,还让我深刻的体会到了线性表的重要性以及其应用的方便,并且对指针加深了映象,应用了书本中的算法思想,对我以后的编译以及完成新的程序有很大的帮助。 附录: 1.建立多项式列表代码如下: mulpoly *creatpoly()/*建立多项式列表*/ {mulpoly *head,*r,*s;/*设中间变量*/ int m,n; head=(mulpoly *)malloc(sizeof(mulpoly));/*头结点申请空间*/ printf("\ninput coef and exp:\n"); scanf("%d%d",&n,&m);/*输入多项式系数和指数*/ r=head;/*尾指针指向头指针*/ while(n!=0)/*将输入的多项式存放在S中*/ {s=(mulpoly*)malloc(sizeof(mulpoly)); s->coef=n; s->exp=m; r->next=s; r=s; /*printf("input coef and exp:\n");*/ scanf("%d%d",&n,&m);/*再次输入多项式系数和指数*/ } r->next=NULL;/*将尾指针置空*/ head=head->next;/*将head哑结点向前跑一个结点,使其不为空*/ return (head);/*返回多项式*/ } 2.两个多项式相加代码如下: mulpoly *polyadd(mulpoly *ha,mulpoly *hb)/*两个多项式相加*/ {mulpoly *hc,*p,*q,*s,*r;/*声明结构体型*/ int x; p=ha; q=hb; hc=(mulpoly *)malloc(sizeof(mulpoly));/*申请结点空间*/ s=hc; while((p!=NULL)&&(q!=NULL))/*两多项式不为空*/
符号多项式的操作,已经成为表处理的典型用例。在数学上,一个一元多项式Pn(x)可按升幂写 成: Pn(x) = p0+ p1x+ p2x2+….+ pnxn 它由n+1个系数唯一确定,因此,在计算机里,它可用一个线 性表P来表示: P = (p0 ,p1 ,p2 ,… pn)每一项的指数i隐含在其系数pi的序号里。 假设Qm(x)是一元m次多项式,同样可用线性表Q来表示:Q = (q0 ,q1 ,q2 ,… qm)。 不失一般性,设m<n,则两个多项式相加的结果 Rn(x) = Pn(x)+Qm(x)可用线性表R表示:R = (p0+q0 , p1+q1 , p2 +q2 , … , pm +qm , pm+1 ,… pn)。显然,我们可以对P、Q和R采用顺序存储结构, 使得多项式相加算法定义十分简洁。至此,一元多项式的表示及相加问题似乎已经解决了。 然而在通常的应用中,多项式的次数可能很高且变化很大,使得顺序存储结构的最大长度很难 决定。特别是在处理形如:S(x) = 1+3x10000+2x20000的多项式时,就要用一长度为20001的线性表来 表示,表中仅有三个非零元素,这种对内存空间的浪费是应当避免的,但是如果只存储非零系数项 则显然必须同时存储相应的指数。 一般情况下的一元n次多项式可写成: Pn(x) = p1x e1 + p2x e2 + … + pmx em 其中 pi,是指数为 ei 的项的非零系数,且满足 0 ≤ e1 < e2 < …< em = n,若用一个长度为 m 且 每个元素有两个数据项(系数项和指数项)的线性表便可唯一确定多项式 Pn(x)。 ((p1 ,e1) , (p2 ,e2) , … ,(pm,em)) 在最坏情况下,n+1(=m)个系数都不为零,则比只存储每项系数的方案要多存储一倍的数据。但 是,对于 S(x)类的多项式,这种表示将大大节省空间。 本题要求选用线性表的一种合适的存储结构来表示一个一元多项式,并在此结构上实现一元多 项式的加法,减法和乘法操作

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值