一元多项式的链式表示-C语言实现

目录

一、前言与思考

二、实现基本操作

三、完整代码


一、前言与思考

思考:f(x)=4+3x+x^2,如何保存?

1.顺序表:只保存系数,指数就是下标,如图所示。

有效数据为3,总长度为5(5个格子)

问题:如果多项式为h(x)=1+3x^100+4x^200,这样的多项式过于稀疏,存储起来会浪费内存,顺序表长度至少为201,但是只存储了3个数字。因此选用链表

2. 链表:每个节点数据保存系数+指数,如图所示。

好处:多项式主要是用来进行运算,链表的插入和删除操作相对于顺序表更方便

二、实现基本操作

多项式的加法、减法、插入、删除、查找、输出。

定义:

// 定义
typedef struct
{
	float coef;//系数
	int expn;//指数
} ElemType;//类型名 ElemType为Linklist的数据对象名

typedef struct PNode
{
	ElemType data;//数据 (系数+指数)
	struct PNode* next;//后继指针
}PNode, * Poly;

 初始化:

跟链表操作一样,断言不为空,令next=NULL;


//初始化多项式:数据域置空
void InitPoly(Poly po)
{
	assert(po != NULL);
	if (po == NULL)
		return;
	po->next = NULL;
}

输出:

循环遍历,输出data域

//输出多项式
void Show(Poly po)
{
	for (PNode* p = po->next; p != NULL; p = p->next)
	{
		printf("%4.1fx^%d + ", p->data.coef, p->data.expn);//4.1保存一位小数
	}
	printf("\n");
}

查找函数:

//查找指数相同的结点,并返回该节点

以下为待完善代码,完整版代码在最后面:

static PNode* Search(Poly po, int expn)

{

        for (pNode* p = po->next; p != NULL; p = p->next)

        {

                if (p->data.expn == expn)

                        return p;//找到了

                else if (p->data.expn > expn)

                        return NULL;

        }

        return NULL;

}

问题:

1.合并同类项:系数为0->删除该结点(删除依赖于前驱)

因此,修改Search函数为查找前驱函数

//查找结点前驱函数

static PNode* SearchPrior(Poly po, int expn)

{

        for (pNode* p = po->next; p->next != NULL; p = p->next)

        {

                if (p->next->data.expn == expn)

                        return p;//找到了

                else if (p->next->data.expn > expn)

                        return NULL;

}

        return NULL;

}

问题:

  1. 中间插入结点:若指数位于已有的指数中间项,需插入结点到两节点之间的位置。根据上述代码,会执行else if内函数,返回NULL。需要修改的是将返回值返回为当前结点,return p;
  2. 尾部插入:若指数比已有的指数大,需插入节点到尾部节点之后。根据上述代码,会跳出for循环,执行return NULL。需要修改代码返回当前结点,return p;

注意:

查找函数是为了后面插入函数而铺垫的,因为需要考虑对插入函数的三种情况:

  1. 如果待插入结点和查找的结点系数一致,应返回查找结点前驱结点
  2. 如果待插入结点比查找的结点系数小,应返回查找结点前驱结点,把待插入结点放在该节点前驱与该节点之间位置
  3. 如果待插入结点比查找的结点系数大,返回该链表最后一个结点,把带插入节点放在最后一个结点后面。

 最终函数完整版为:

//在po中查找指数为expn的节点前驱,如果存在返回节点地址,不存在返回NULL
static PNode* SearchPrior(Poly po, int expn)
{
	PNode* p;
	for (p = po; p->next != NULL; p = p->next)
	{
		if (p->next->data.expn == expn)
			return p;
		else if (p->next->data.expn > expn)
			return p;//return NULL;
	}
	return p;
}

 插入函数:

说明:

调用SearchPrior函数返回查找后的结点,就不必再循环查找结点,直接将该结点进行判断即可

1.如果指数相同p->data.expn == val.expn,合并同类项:

系数相加减p->data.coef+=val.coef,如果加减之后系数之和为0,剔除该节点->剔除结点需要该节点的前驱,引入新结点PNode* q = p->next

2.如果指数不同p->data.expn != val.expn

判断该节点与已有结点的关系:如果该节点的指数位于已有节点之间,将该节点插入在中间;如果该节点的指数大于已有的最大结点的指数,将该结点插入在尾部。

补充:

1.C语言中浮点数有误差问题,要判断很小的范围以内,定义宏#define EPS 0.0000001,含义:在这个数以内,视为0

 2.函数设计:引入flag的原因,后面有对多项式进行加减操作,调用该函数,flag用来保存符号位


//往po多项式插入数据val,按指数升序
bool Insert(Poly po, ElemType val, int flag)//flag标记正负号
{
#define EPS 0.0000001//在这个数以内,视为0
	if (-EPS <= val.coef && val.coef <= EPS)
		return false;

	//PNode* p;
	PNode* p = SearchPrior(po, val.expn);//调用上面SearchPrior函数返回查找后的结点
	PNode* q = p->next;//剔除结点需要前驱
	/*调用SearchPrior函数返回查找后的结点,就不必再循环查找结点,直接将该结点进行判断即可
	*如果不调用SearchPrior函数,直接定义新结点p,会导致PNode* q = p->next出错
	*/
	//for (p = po; p->next != NULL; p = p->next)
	if (q != NULL && q->data.expn == val.expn)//指数相同
	{
		//q->data.coef += val.coef * flag;
		q->data.coef = q->data.coef + val.coef * flag;
		if (-EPS <= q->data.coef && q->data.coef <= EPS)//系数为0,删除该节点
		{
			p->next = q->next;//剔除q
			free(q);
		}
	}
	else//指数不同
	{
		//动态创建内存q,将q作为新结点插入进链表
		q = (PNode*)malloc(sizeof(PNode));
		assert(q != NULL);
		if (q == NULL)
			return false;

		q->data = val;

		q->next = p->next;
		p->next = q;
	}
	return true;
}

加法:

说明:

调用插入函数即可

//po2+po1
bool Add(Poly po1, Poly po2)
{
	for (PNode* p = po2->next; p != NULL; p = p->next)
		Insert(po1, p->data, +1);
	return true;
}

减法:

系数改为负数即可 

bool Sub(Poly po1, Poly po2)
{
	for (PNode* p = po2->next; p != NULL; p = p->next)
		Insert(po1, p->data, -1);
	return true;
}

销毁:

//销毁多项式po
void Destroy(Poly po)
{
	if (po == NULL || po->next == NULL)
		return;
	PNode* p = po->next;
	while (po->next != NULL)
	{
		p = po->next;
		po->next = p->next;
		free(p);
	}
}

三、完整代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

// 定义
typedef struct
{
	float coef;//系数
	int expn;//指数
} ElemType;//类型名 ElemType为Linklist的数据对象名

typedef struct PNode
{
	ElemType data;//数据 (系数+指数)
	struct PNode* next;//后继指针
}PNode, * Poly;

// 初始化多项式
void InitPoly(Poly po)
{
	assert(po != NULL);
	if (po == NULL)
		return;
	po->next = NULL;
}

//查找结点前驱函数
//在po中查找指数为expn的节点前驱,如果存在返回节点地址,不存在返回NULL
static PNode* SearchPrior(Poly po, int expn)
{
	PNode* p;
	for (p = po; p->next != NULL; p = p->next)
	{
		if (p->next->data.expn == expn)
			return p;
		else if (p->next->data.expn > expn)
			return p;//return NULL;
	}
	return p;
}

//往po多项式插入数据val,按指数升序
bool Insert(Poly po, ElemType val, int flag)//flag标记正负号,1->正数,-1->负数
{
#define EPS 0.0000001//在这个数以内,视为0
	if (-EPS <= val.coef && val.coef <= EPS)
		return false;

	//PNode* p;
	PNode* p = SearchPrior(po, val.expn);//调用上面SearchPrior函数返回查找后的结点
	PNode* q = p->next;//剔除结点需要前驱
	/*调用SearchPrior函数返回查找后的结点,就不必再循环查找结点,直接将该结点进行判断即可
	*如果不调用SearchPrior函数,直接定义新结点p,会导致PNode* q = p->next出错
	*/
	//for (p = po; p->next != NULL; p = p->next)
	if (q != NULL && q->data.expn == val.expn)//指数相同
	{
		//q->data.coef += val.coef * flag;
		q->data.coef = q->data.coef + val.coef * flag;
		if (-EPS <= q->data.coef && q->data.coef <= EPS)//系数为0,删除该节点
		{
			p->next = q->next;//剔除q
			free(q);
		}
	}
	else//指数不同
	{
		//动态创建内存q,将q作为新结点插入进链表
		q = (PNode*)malloc(sizeof(PNode));
		assert(q != NULL);
		if (q == NULL)
			return false;

		q->data = val;

		q->next = p->next;
		p->next = q;
	}
	return true;
}

//输出多项式
void Show(Poly po)
{
	for (PNode* p = po->next; p != NULL; p = p->next)
	{
		printf("%4.1fx^%d + ", p->data.coef, p->data.expn);//4.1保存一位小数
	}
	printf("\n");
}

//po2+po1
bool Add(Poly po1, Poly po2)
{
	for (PNode* p = po2->next; p != NULL; p = p->next)
		Insert(po1, p->data, +1);
	return true;
}
//减法
//系数改为负数
bool Sub(Poly po1, Poly po2)
{
	for (PNode* p = po2->next; p != NULL; p = p->next)
		Insert(po1, p->data, -1);
	return true;
}

//销毁多项式po
void Destroy(Poly po)
{
	if (po == NULL || po->next == NULL)
		return;
	PNode* p = po->next;
	while (po->next != NULL)// (p!=plist)
	{
		p = po->next;
		po->next = p->next;
		free(p);
	}
}


int main()
{
	PNode po;
	InitPoly(&po);
	ElemType arr[] = { {1,0},{2,10},{3,20},{4,5},{5,200},{-3,20} };//{1,0}x的0次方,{2,10}2x^10...
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		Insert(&po, arr[i], 1);
	}
	PNode po2;
	InitPoly(&po2);
	ElemType arr2[] = { {4,0},{5,1},{6,200},{7,500} };
	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
	{
		Insert(&po2, arr2[i], 1);
	}
	printf("多项式1为:\n");
	Show(&po);
	printf("多项式2为:\n");
	Show(&po2);
	//对加法测试
	Add(&po, &po2);
	printf("多项式1+多项式2为:\n");
	Show(&po);
	//对减法测试
	Sub(&po, &po2);
	printf("多项式1-多项式2为:\n");
	Show(&po);
	return 0;
}

测试结果:

注释:多项式后面的“+”是在输出函数为了连接的操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值