数据结构学习笔记 --- 线性表 (一元多项式的表示及相加)

1. 引言 


本文主要讲解一元多项式的表示及相加。


2. 一元多项式的表示和及相加


/* 一元多项式的表示和相加 */
#include "ds.h"
using namespace std;


#ifdef TEST_LIST
typedef 	int 	 ElemType;
#else
typedef struct {
	float 	coef; 	//系数
	int 	expn; 	//指数
}term, ElemType;  	// 两个类型名:term用于本ADT,ElemType为LinkList的数据对象名

#endif

typedef struct LNode{
	ElemType 		data;
	struct LNode	*next;
}LNode, *Link, *Position;

typedef struct {
	Link 		head, tail;
	int			len;
}LinkList;

#ifndef TEST_LIST
typedef LinkList polynomial;
#define DestroyPolyn DestroyList // 与bo2-6.cpp中的函数同义不同名
#define PolynLength ListLength // 与bo2-6.cpp中的函数同义不同名
#endif

void MakeNode(Link &p, ElemType e);
void FreeNode(Link &p);
void InitList(LinkList &L);
void ClearList(LinkList &L);
void DestroyList(LinkList &L);
// h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前, 形参增加L,因为需修改L
void InsFirst(LinkList &L,Link h,Link s);
// h指向L的一个结点,把h当做头结点,删除链表中的第一个结点并以q返回。
// 若链表为空(h指向尾结点),q=NULL,返回FALSE
Status DelFirst(LinkList &L, Link h, Link &q);

// 将指针s(s->data为第一个数据元素)所指(彼此以指针相链,以NULL结尾)的
// 一串结点链接在线性链表L的最后一个结点之后,并改变链表L的尾指针指向新的尾结点
void Append(LinkList &L, Link s);
// 已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置。若无前驱,则返回NULL
Position PriorPos(LinkList L, Link p);
// 删除线性链表L中的尾结点并以q返回,改变链表L的尾指针指向新的尾结点
Status Remove(LinkList &L, Link &q);
// 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前,
// 并修改指针p指向新插入的结点
void InsBefore(LinkList &L, Link &p, Link s);

// 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后,
// 并修改指针p指向新插入的结点
void InsAfter(LinkList &L,Link &p,Link s);
// 已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值
void SetCurElem(Link p, ElemType e);
ElemType GetCurElem(Link p);
Status ListEmpty(LinkList L);
int ListLength(LinkList L);
Position NextPos(Link p);
Position GetHead(LinkList L);
Position GetLast(LinkList L);
// 返回p指示线性链表L中第i个结点的位置,并返回OK,i值不合法时返回ERROR。i=0为头结点
Status LocatePos(LinkList L, int i, Link &p);
// 返回线性链表L中第1个与e满足函数compare()判定关系的元素的位置,
// 若不存在这样的元素,则返回NULL
Position LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType));

void ListTraverse(LinkList L, void(*visit)(ElemType) );
// 已知L为有序线性链表,将元素e按非降序插入在L中。
void OrderInsert(LinkList &L, ElemType e, int (*com)(ElemType, ElemType));
// 若升序链表L中存在与e满足判定函数compare()取值为0的元素,则q指示L中
// 第一个值为e的结点的位置,并返回TRUE;否则q指示第一个与e满足判定函数
// compare()取值>0的元素的前驱的位置。并返回FALSE。(用于一元多项式)
Status LocateElem(LinkList L,ElemType e,Position &q,int(*compare)(ElemType,ElemType));


void MakeNode(Link &p, ElemType e)
{
	p = (Link)malloc(sizeof(LNode));
	if (!p)
		exit(ERROR);
	memcpy(&(p->data), &e, sizeof(ElemType));
	p->next = NULL;
}
void FreeNode(Link &p)
{
	free(p);
	p = NULL;
}

// 带头结点的单链表
void InitList(LinkList &L)
{
	Link 	p;
	p = (Link)malloc(sizeof(LNode));  //生成头结点
	if (p)
	{
		L.head = L.tail = p;
		L.tail->next = NULL;
		L.len = 0;
	}
	else
		exit(ERROR);
}
void ClearList(LinkList &L)
{
	Link 	q, p = L.head->next;
	
	if (0 == L.len)
		return;
	
	L.head->next = NULL;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	
	L.tail = L.head;
	L.len = 0;
}
void DestroyList(LinkList &L)
{
	ClearList(L);
	FreeNode(L.head);
	L.tail = NULL;
	L.len = 0;
}
// h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前, 形参增加L,因为需修改L
void InsFirst(LinkList &L,Link h,Link s)
{
	s->next = h->next;
	h->next = s;
	if (h == L.tail)
		L.tail = h->next;
	L.len++;
}
// h指向L的一个结点,把h当做头结点,删除链表中的第一个结点并以q返回。
// 若链表为空(h指向尾结点),q=NULL,返回FALSE
Status DelFirst(LinkList &L, Link h, Link &q)
{
#if 0	
	q = h->next;
	if (h == L.tail)
		return FALSE;
	
	h->next = q->next;
	if (!q->next)
		L.tail = h;
	
	L.len--;
	return OK;
#endif 
	q=h->next;
   if(q) // 链表非空
   {
     h->next=q->next;
     if(!h->next) // 删除尾结点
       L.tail=h; // 修改尾指针
     L.len--;
     return OK;
   }
   else
     return FALSE; // 链表空
}

// 将指针s(s->data为第一个数据元素)所指(彼此以指针相链,以NULL结尾)的
// 一串结点链接在线性链表L的最后一个结点之后,并改变链表L的尾指针指向新的尾结点
void Append(LinkList &L, Link s)
{
	int 	i = 1;
	
	L.tail->next = s;
	
	if (NULL == s)
		return;
	
	while (s->next)
	{
		s = s->next;
		i++;
	}
	
	L.tail = s;
	L.len += i;
}
// 已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置。若无前驱,则返回NULL
Position PriorPos(LinkList L, Link p)
{
	Link 	q = L.head->next;
	
	if (!L.len || 1 == L.len)
		return NULL;
	
	while (q->next && q->next != p)
	{
		q = q->next;
	}
	
	if (!q->next)
		return NULL;
	
	return q;
}

// 删除线性链表L中的尾结点并以q返回,改变链表L的尾指针指向新的尾结点
Status Remove(LinkList &L, Link &q)
{
	Link 	p = L.head;
	q = L.tail;
	
	if (!L.len)
	{
		q = NULL;
		return ERROR;
	}
	while (p->next != L.tail)
	{
		p = p->next;
	}
	
	p->next = NULL;
	L.tail = p;
	
	L.len--;
	return OK;
}
// 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前,
// 并修改指针p指向新插入的结点
void InsBefore(LinkList &L, Link &p, Link s)
{
	Link 	pp = L.head;
	
	while (pp->next && pp->next != p)
		pp = pp->next;
	
	if (pp->next)
	{
		s->next = pp->next;
		pp->next = s;
	}
	else
		return;
	p = s;
	L.len++;
}

// 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后,
// 并修改指针p指向新插入的结点
void InsAfter(LinkList &L,Link &p,Link s)
{
	if (p == L.tail)
	{
		s->next = p->next;
		p->next = s;
		L.tail = s;
	}
	else
	{
		s->next = p->next;
		p->next = s;
	}
	
	p = s;
	L.len++;
}
// 已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值
void SetCurElem(Link p, ElemType e)
{
	memcpy(&(p->data), &e, sizeof(ElemType));
}
ElemType GetCurElem(Link p)
{
	return p->data;
}
Status ListEmpty(LinkList L)
{
	if (L.len)
		return FALSE;
	else
		return TRUE;
	
}
int ListLength(LinkList L)
{
	return L.len;
}
Position GetHead(LinkList L)
{
	return L.head;
}
Position GetLast(LinkList L)
{
	return L.tail;
}
Position NextPos(Link p)
{
	return p->next;
}
// 返回p指示线性链表L中第i个结点的位置,并返回OK,i值不合法时返回ERROR。i=0为头结点
Status LocatePos(LinkList L, int i, Link &p)
{
	int 	j = 0;
	
	if (i < 0 || i > L.len)
		return ERROR;
	p = L.head;
	for (; j < i; j++)
		p = p->next;
	
	return OK;
}

// 返回线性链表L中第1个与e满足函数compare()判定关系的元素的位置,
// 若不存在这样的元素,则返回NULL
Position LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType))
{
	Link 		p = L.head->next;
	
	while (p && !compare(e, p->data))
		p = p->next;
	
	if (!p)
		return NULL;
	
	return p;
}

void ListTraverse(LinkList L, void(*visit)(ElemType) )
{
	Link 	p = L.head->next;
	
	while (p)
	{
		visit(p->data);
		p = p->next;
	}
	printf("\n");
}

// 已知L为有序线性链表,将元素e按非降序插入在L中。
void OrderInsert(LinkList &L, ElemType e, int (*comp)(ElemType, ElemType))
{
#if 1	
	Link 	q = L.head, s;
	Link 	p = q->next;
	
	MakeNode(s, e);
	
	while (p && comp(p->data, e) < 0) // p不是表尾且元素值小于e
	{
		q = p;
		p = p->next;
	}
	
	q->next = s;
	s->next = p;
	
	if (!p)  // 插在表尾
		L.tail = s;  // 修改尾结点
	
	L.len++;
#else
	Link o,p,q;
   q=L.head;
   p=q->next;
   while(p!=NULL&&comp(p->data,e)<0) // p不是表尾且元素值小于e
   {
     q=p;
     p=p->next;
   }
   o=(Link)malloc(sizeof(LNode)); // 生成结点
   o->data=e; // 赋值
   q->next=o; // 插入
   o->next=p;
   L.len++; // 表长加1
   if(!p) // 插在表尾
     L.tail=o; // 修改尾结点
#endif
}
// 若升序链表L中存在与e满足判定函数compare()取值为0的元素,则q指示L中
// 第一个值为e的结点的位置,并返回TRUE;否则q指示第一个与e满足判定函数
// compare()取值>0的元素的前驱的位置。并返回FALSE。(用于一元多项式)
Status LocateElem(LinkList L,ElemType e,Position &q,int(*compare)(ElemType,ElemType))
{
	Link 	p = L.head;
	
	do
	{
		q = p;
		p = p->next;
	}while (p && compare(p->data, e) < 0);
	
	if (p && compare(p->data, e) == 0)
	{
		q = p;
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

#ifdef TEST_LIST
void print(ElemType e)
{
	printf("%d ", e);
}

int comp(ElemType a, ElemType b)
{
	return a-b;
}

Status equal(ElemType c1,ElemType c2)
{ // 判断是否相等的函数
   if(c1==c2)
     return TRUE;
   else
     return FALSE;
 }
#else
	
 void PrintPolyn(polynomial P)
 { // 打印输出一元多项式P
   Link q;
   q=P.head->next; // q指向第1个结点
   printf("  系数    指数\n");
   while(q)
   {
     printf("%f  %d\n",q->data.coef,q->data.expn);
     q=q->next;
   }
 }
	
int cmp(term a,term b) // CreatPolyn()的实参
 { // 依a的指数值<、=或>b的指数值,分别返回-1、0或+1
   if(a.expn==b.expn)
     return 0;
   else
     return (a.expn-b.expn)/abs(a.expn-b.expn);
 }
	

#endif


 void OrderInsertMerge(LinkList &L,ElemType e,int(* compare)(term,term))
 { // 按有序判定函数compare()的约定,将值为e的结点插入或合并到升序链表L的适当位置
   Position q,s;
   if(LocateElem(L,e,q,compare)) // L中存在该指数项
   {
     q->data.coef+=e.coef; // 改变当前结点系数的值
     if(!q->data.coef) // 系数为0
     { // 删除多项式L中当前结点
       s=PriorPos(L,q); // s为当前结点的前驱
       if(!s) // q无前驱
         s=L.head;
       DelFirst(L,s,q);
       FreeNode(q);
     }
   }
   else // 生成该指数项并插入链表
   {
     MakeNode(s,e); // 生成结点
     InsFirst(L,q,s);
   }
 }

 
 void CreatPolyn(polynomial &P,int m) // 算法2.22
 { // 输入m项的系数和指数,建立表示一元多项式的有序链表P
   Position q,s;
   term e;
   int i;
   InitList(P);
   printf("请依次输入%d个系数,指数:\n",m);
   for(i=1;i<=m;++i)
   { // 依次输入m个非零项(可按任意顺序)
     scanf("%f,%d",&e.coef,&e.expn);
     if(!LocateElem(P,e,q,cmp)) // 当前链表中不存在该指数项,cmp是实参
     {
       MakeNode(s,e); // 生成结点并插入链表
       InsFirst(P,q,s);
	 }
   }
 }

 void AddPolyn(polynomial &Pa,polynomial &Pb) // 算法2.23
 { // 多项式加法:Pa=Pa+Pb,并销毁一元多项式Pb
   Position ha,hb,qa,qb;
   term a,b;
   ha=GetHead(Pa);
   hb=GetHead(Pb); // ha和hb分别指向Pa和Pb的头结点
   qa=NextPos(ha);
   qb=NextPos(hb); // qa和qb分别指向Pa和Pb中当前结点(现为第1个结点)
   while(!ListEmpty(Pa)&&!ListEmpty(Pb)&&qa)
   { // Pa和Pb均非空且ha没指向尾结点(qa!=0)
     a=GetCurElem(qa);
     b=GetCurElem(qb); // a和b为两表中当前比较元素
     switch(cmp(a,b))
     {
       case -1:ha=qa; // 多项式Pa中当前结点的指数值小
               qa=NextPos(ha); // ha和qa均向后移1个结点
               break;
       case 0: qa->data.coef+=qb->data.coef; // 两者的指数值相等,修改Pa当前结点的系数值
               if(qa->data.coef==0) // 删除多项式Pa中当前结点
               {
                 DelFirst(Pa,ha,qa);
		 FreeNode(qa);
               }
               else
                 ha=qa;
               DelFirst(Pb,hb,qb);
               FreeNode(qb);
               qb=NextPos(hb);
               qa=NextPos(ha);
               break;
       case 1: DelFirst(Pb,hb,qb); // 多项式Pb中当前结点的指数值小
               InsFirst(Pa,ha,qb);
               ha=ha->next;
               qb=NextPos(hb);
     }
   }
   if(!ListEmpty(Pb))
   {
	 qa = qb;
     Pb.tail=hb;
     Append(Pa,qa); // 链接Pb中剩余结点
   }
   DestroyPolyn(Pb); // 销毁Pb
 }

 void AddPolyn1(polynomial &Pa,polynomial &Pb)
 { // 另一种多项式加法的算法:Pa=Pa+Pb,并销毁一元多项式Pb
   Position qb;
   term b;
   qb=GetHead(Pb); // qb指向Pb的头结点
   qb=qb->next; // qb指向Pb的第1个结点
   while(qb)
   {
     b=GetCurElem(qb);
     OrderInsertMerge(Pa,b,cmp);
     qb=qb->next;
   }
   DestroyPolyn(Pb); // 销毁Pb
 }

 void Opposite(polynomial &Pa)
 { // 一元多项式Pa系数取反
   Position p;
   p=Pa.head;
   while(p->next)
   {
     p=p->next;
     p->data.coef*=-1;
   }
 }

 void SubtractPolyn(polynomial &Pa,polynomial &Pb)
 { // 多项式减法:Pa=Pa-Pb,并销毁一元多项式Pb
   Opposite(Pb);
   AddPolyn1(Pa,Pb);
 }

 void MultiplyPolyn(polynomial &Pa,polynomial &Pb)
 { // 多项式乘法:Pa=Pa×Pb,并销毁一元多项式Pb
   polynomial Pc;
   Position qa,qb;
   term a,b,c;
   InitList(Pc);
   qa=GetHead(Pa);
   qa=qa->next;
   while(qa)
   {
     a=GetCurElem(qa);
     qb=GetHead(Pb);
     qb=qb->next;
     while(qb)
     {
       b=GetCurElem(qb);
       c.coef=a.coef*b.coef;
       c.expn=a.expn+b.expn;
       OrderInsertMerge(Pc,c,cmp);
       qb=qb->next;
     }
     qa=qa->next;
   }
   DestroyPolyn(Pb); // 销毁Pb
   ClearList(Pa); // 将Pa重置为空表
   Pa.head=Pc.head;
   Pa.tail=Pc.tail;
   Pa.len=Pc.len;
 }


#ifdef TEST_LIST
int main()
 {
   Link p,h;
   LinkList L;
   Status i;
   int j,k;
   InitList(L); // 初始化空的线性表L
   for(j=1;j<=2;j++)
   {
     MakeNode(p,j); // 生成由p指向、值为j的结点
     InsFirst(L,L.tail,p); // 插在表尾
   }
    ListTraverse(L,print); // 输出L
   cout << "L'length:"<< ListLength(L) << endl;
   
   OrderInsert(L,0,comp); // 按升序插在有序表头
   
    ListTraverse(L,print); // 输出L
   cout << "L'length:"<< ListLength(L) << endl;
   for(j=0;j<=3;j++)
   {
     i=LocateElem(L,j,p,comp);
     if(i)
       printf("链表中有值为%d的元素。\n",p->data);
     else
       printf("链表中没有值为%d的元素。\n",j);
   }
   printf("输出链表:");
   ListTraverse(L,print); // 输出L
   cout << "L'length:"<< ListLength(L) << endl;
   for(j=1;j<=4;j++)
   {
     printf("删除表头结点:");
     DelFirst(L,L.head,p); // 删除L的首结点,并以p返回
     if(p)
       printf("%d\n",GetCurElem(p));
     else
       printf("表空,无法删除 p=%u\n",p);
   }
   printf("L中结点个数=%d L是否空 %d(1:空 0:否)\n",ListLength(L),ListEmpty(L));
   MakeNode(p,10);
   p->next=NULL; // 尾结点
   for(j=4;j>=1;j--)
   {
     MakeNode(h,j*2);
     h->next=p;
     p=h;
   } // h指向一串5个结点,其值依次是2 4 6 8 10
   Append(L,h); // 把结点h链接在线性链表L的最后一个结点之后
   OrderInsert(L,12,comp); // 按升序插在有序表尾头
   OrderInsert(L,7,comp); // 按升序插在有序表中间
   printf("输出链表:");
   ListTraverse(L,print); // 输出L
   for(j=1;j<=2;j++)
   {
     p=LocateElem(L,j*5,equal);
     if(p)
       printf("L中存在值为%d的结点。\n",j*5);
     else
       printf("L中不存在值为%d的结点。\n",j*5);
   }
   for(j=1;j<=2;j++)
   {
     LocatePos(L,j,p); // p指向L的第j个结点
     h=PriorPos(L,p); // h指向p的前驱
     if(h)
       printf("%d的前驱是%d。\n",p->data,h->data);
     else
       printf("%d没前驱。\n",p->data);
   }
   k=ListLength(L);
   for(j=k-1;j<=k;j++)
   {
     LocatePos(L,j,p); // p指向L的第j个结点
     h=NextPos(p); // h指向p的后继
     if(h)
       printf("%d的后继是%d。\n",p->data,h->data);
     else
       printf("%d没后继。\n",p->data);
   }
   printf("L中结点个数=%d L是否空 %d(1:空 0:否)\n",ListLength(L),ListEmpty(L));
   p=GetLast(L); // p指向最后一个结点
   SetCurElem(p,15); // 将最后一个结点的值变为15
   printf("第1个元素为%d 最后1个元素为%d\n",GetCurElem(GetHead(L)->next),GetCurElem(p));
   MakeNode(h,10);
   InsBefore(L,p,h); // 将10插到尾结点之前,p指向新结点
   p=p->next; // p恢复为尾结点
   MakeNode(h,20);
   InsAfter(L,p,h); // 将20插到尾结点之后
   k=ListLength(L);
   printf("依次删除表尾结点并输出其值:");
   for(j=0;j<=k;j++)
     if(!(i=Remove(L,p))) // 删除不成功
       printf("删除不成功 p=%u\n",p);
     else
       printf("%d ",p->data);
   MakeNode(p,29); // 重建具有1个结点(29)的链表
   InsFirst(L,L.head,p);
   DestroyList(L); // 销毁线性链表L
   printf("销毁线性链表L之后: L.head=%u L.tail=%u L.len=%d\n",L.head,L.tail,L.len);
 }
#else

int main()
 {
   polynomial p,q;
   int m;
   printf("请输入第1个一元多项式的非零项的个数:");
   scanf("%d",&m);
   CreatPolyn(p,m);
   printf("请输入第2个一元多项式的非零项的个数:");
   scanf("%d",&m);
   CreatPolyn(q,m);
   AddPolyn(p,q);
   //SubtractPolyn(p,q);
   printf("2个一元多项式相加的结果:\n");
   PrintPolyn(p);


   
   printf("请输入第3个一元多项式的非零项的个数:");
   scanf("%d",&m);
   CreatPolyn(q,m);
   AddPolyn1(p,q);
   printf("2个一元多项式相加的结果(另一种方法):\n");
   PrintPolyn(p);
   printf("请输入第4个一元多项式的非零项的个数:");
   scanf("%d",&m);
   CreatPolyn(q,m);
   SubtractPolyn(p,q);
   printf("2个一元多项式相减的结果:\n");
   PrintPolyn(p);
   printf("请输入第5个一元多项式的非零项的个数:");
   scanf("%d",&m);
   CreatPolyn(q,m);
   MultiplyPolyn(p,q);
   printf("2个一元多项式相乘的结果:\n");
   PrintPolyn(p);
   DestroyPolyn(p);
   
 }

#endif
	


  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值