1.稀疏多项式回顾
1.稀疏多项式的定义
多项式中指数由低到高排列 ,每一项的系数非零的多项式
比如:
2.顺序存储与链式存储的优劣辨析:
我们可以使用顺序表来存储整个多项式,同样可以使用链表来存储整个多项式
- 但是由于顺序表存在以下劣势,故本篇使用链表来存储
2.稀疏多项式加法运算 的 链式实现
1.稀疏多项式结点的结构定义:
typedef struct Node
{
double coef;//系数
int expen;//指数
struct Node* next;//指针域
}Node,* Polynomial;
//Polynomial:多项的
与一般的链表结点相同,只不过稀疏多项式结点数据域分为指数和系数两部分
2.通过用户输入建立稀疏多项式算法(系数按照非递减有序排列)
注意:由于要创建新链表,故传入二级指针
void CreatePolynomial(Polynomial *L,int n)
1.算法步骤:
(1)创建只有一个头结点的空链表(注意初始化)
(2)定义三个临时指针:
//s:用来建立新结点
//pre:用来指向待插入结点的前一个结点:第一个 (指数大于 待插入结点的 结点)的前一个结点
//q:用来指向待插入结点的后一个结点:第一个 指数大于 待插入结点的 结点
(3)循环并按照非递减有序排列插入结点(核心)
<1>建立并初始化新结点的系数与指数
<2>每次初始化 pre指向头结点(寻找待插入前驱);q指向当前首元结点(寻找待插入后继)
<3>遍历链表,寻找插入位置(q指向待插入位置的后一个结点)(pre指向待插入位置的前一个结点)
<4>将新结点插入到链表中正确位置中,即pre和q之间
//1.系数按照非递减有序排列 建立多项式
//核心:对于待插入结点 及其前一结点 和 后一结点的相关操作
void CreatePolynomial(Polynomial *L,int n)
{
//[1]创建只有一个头结点的空链表
(*L) = (Polynomial)malloc(sizeof(Node));
if (!(*L))
{
return -1;//程序非正常返回
}
(*L)->next = NULL;
//[2]定义三个临时指针:
//s:用来建立新结点
//pre:用来指向待插入结点的前一个结点:第一个 (指数大于 待插入结点的 结点)的前一个结点
//q:用来指向待插入结点的后一个结点:第一个 指数大于 待插入结点的 结点
Node* s,* pre,* q;
//[3]循环并按照非递减有序排列插入结点
for(int i=0;i<n;i++)
{
//<1>建立并初始化新结点的系数与指数
s = (Node*)malloc(sizeof(Node));
if (!s)
{
return -1; //程序非正常返回
}
printf("输入第%d项的系数和指数:\n",i+1);
scanf_s("%lf %d", &s->coef, &s->expen);
//<2>每次初始化 pre指向头结点(寻找待插入前驱);q指向当前首元结点(寻找待插入后继)
pre = (*L);
q = (*L)->next;
//<3>遍历链表,寻找插入位置(q指向待插入位置的后一个结点)(pre指向待插入位置的前一个结点)
while (q && q->expen < s->expen)//寻找 第一个 指数 大于 待插入的结点指数 的结点
{
pre = q;
q = q->next;
}
//<4>将新结点插入到链表中正确位置中,即pre和q之间
s->next = q;
pre->next = s;
}
}
3.多项式的相加算法(实际上为 有序表的合并操作 的实际应用)
void addpolynomial(Polynomial * La, Polynomial * Lb, Polynomial * Lc)
1.算法步骤:
(0)保证传入两个非空的多项式
(1)初始化pa,pb分别指向La,Lb的首元结点,pc指向新链表的头结点
//pa用来遍历La中的所有结点
//pb用来遍历Lb中的所有结点
//pc用来遍历 新链表中 最新的有效结点(着重注意)
(2)遍历多项式 La 和 Lb,进行相加操作(核心)
<1>若两项指数相等------>进行系数相加操作
<1.1>若系数相加结果为0,跳过并删除当前pa和pb所指向的结点(注意不需要更新pc的指向;因为pc指向的是新链表中 最新的有效结点)
//<1.1.1>临时生成两个指针,用来删除待销毁结点
//<1.1.2>跳过pa所指结点,并更新pa,pb指向下一个结点
//<1.1.3>删除待销毁结点
<1.2>若系数相加结果不为0,修改pa所指结点系数值,同时删除pb所指结点(注意需要更新pc的指向;因为pc指向的是新链表中 最新的有效结点)
//<1.2.1>临时生成1个指针,用来删除待销毁结点
//<1.2.2>修改pa所指结点系数值,作为新的系数
//<1.2.3>修改新链表并保证完整性;同时修改pc的指向,指向最新的有效结点;更新pa,pb指向下一个结点
//<1.2.4>删除待销毁结点
<2>若pa指向的结点指数值 小于 pb指向的结点指数值,则将pa指向的结点添加到新链表中(类比升序链表的合并)
<3>若pa指向的结点指数值 大于等于 pb指向的结点指数值,则将pb指向的结点添加到新链表中(类比升序链表的合并)
(3)将非空多项式的剩余结点添加到新链表中最后一个有效结点之后(注意释放Lb的头结点)
//2.多项式的相加算法(实际上为 有序表的合并操作 的实际应用)
void addpolynomial(Polynomial * La, Polynomial * Lb, Polynomial * Lc)
{
//[0]传入两个非空的多项式
if ( (!(*La) || !(*La)->next) || (!(*Lb) || !(*Lb)->next))
{
printf("输入多项式不能为空!\n");
return;
}
//[1]初始化pa,pb分别指向La,Lb的首元结点,pc指向新链表的头结点
//pa用来遍历La中的所有结点
//pb用来遍历Lb中的所有结点
//pc用来遍历 新链表中 最新的有效结点
Node* pa, * pb, * pc;
pa = (*La)->next;
pb = (*Lb)->next;
(*Lc) = (*La);//用La的头结点作为新链表Lc的头结点(当然也可以使用Lb的头结点)
pc = (*Lc);//实际上pc指向的是La的头结点
//[2]遍历多项式 La 和 Lb,进行相加操作
while (pa && pb)
{
//<1>若两项指数相等------>进行系数相加操作
if (pa->expen == pb->expen)
{
double sum = pa->coef + pb->coef;
//<1.1>若系数相加结果为0,跳过并删除当前pa和pb所指向的结点(注意不需要更新pc的指向;因为pc指向的是新链表中 最新的有效结点)
if(sum==0)
{
//<1.1.1>临时生成两个指针,用来删除待销毁结点
Node* temp_pa = pa;
Node* temp_pb = pb;
//<1.1.2>跳过pa所指结点,并更新pa,pb指向下一个结点
pc->next = pa->next;
pa = pa->next;
pb = pb->next;
//<1.1.3>删除待销毁结点
free(temp_pa);
free(temp_pb);
}
//<1.2>若系数相加结果不为0,修改pa所指结点系数值,同时删除pb所指结点(注意需要更新pc的指向;因为pc指向的是新链表中 最新的有效结点)
else
{
//<1.2.1>临时生成1个指针,用来删除待销毁结点
Node* temp_pb = pb;
//<1.2.2>修改pa所指结点系数值,作为新的系数
pa->coef = sum;
//<1.2.3>修改新链表并保证完整性;同时修改pc的指向,指向最新的有效结点;更新pa,pb指向下一个结点
pc->next = pa;
pc = pa;
pa = pa->next;
pb = pb->next;
//<1.2.4>删除待销毁结点
free(temp_pb);
}
}
//<2>若pa指向的结点指数值 小于 pb指向的结点指数值,则将pa指向的结点添加到新链表中(类比升序链表的合并)
else if (pa->expen < pb->expen)
{
pc->next = pa;
pc = pa;
pa = pa->next;
}
//<3>若pa指向的结点指数值 大于等于 pb指向的结点指数值,则将pb指向的结点添加到新链表中(类比升序链表的合并)
else
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
//[3]将非空多项式的剩余结点添加到新链表中最后一个有效结点之后
pc->next = pa ? pa : pb;
free(*Lb);//释放Lb的头结点
}
2.实例图解:
3.整体实现:
//稀疏多项式的相加算法------链式存储结构的实现
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
double coef;//系数
int expen;//指数
struct Node* next;//指针域
}Node,* Polynomial;
//Polynomial:多项的
//1.系数按照非递减有序排列 建立多项式
//核心:对于待插入结点 及其前一结点 和 后一结点的相关操作
void CreatePolynomial(Polynomial *L,int n)
{
//[1]创建只有一个头结点的空链表
(*L) = (Polynomial)malloc(sizeof(Node));
if (!(*L))
{
return -1;//程序非正常返回
}
(*L)->next = NULL;
//[2]定义三个临时指针:
//s:用来建立新结点
//pre:用来指向待插入结点的前一个结点:第一个 (指数大于 待插入结点的 结点)的前一个结点
//q:用来指向待插入结点的后一个结点:第一个 指数大于 待插入结点的 结点
Node* s,* pre,* q;
//[3]循环并按照非递减有序排列插入结点
for(int i=0;i<n;i++)
{
//<1>建立并初始化新结点的系数与指数
s = (Node*)malloc(sizeof(Node));
if (!s)
{
return -1; //程序非正常返回
}
printf("输入第%d项的系数和指数:\n",i+1);
scanf_s("%lf %d", &s->coef, &s->expen);
//<2>每次初始化 pre指向头结点(寻找待插入前驱);q指向当前首元结点(寻找待插入后继)
pre = (*L);
q = (*L)->next;
//<3>遍历链表,寻找插入位置(q指向待插入位置的后一个结点)(pre指向待插入位置的前一个结点)
while (q && q->expen < s->expen)//寻找 第一个 指数 大于 待插入的结点指数 的结点
{
pre = q;
q = q->next;
}
//<4>将新结点插入到链表中正确位置中,即pre和q之间
s->next = q;
pre->next = s;
}
}
//2.多项式的相加算法(实际上为 有序表的合并操作 的实际应用)
void addpolynomial(Polynomial * La, Polynomial * Lb, Polynomial * Lc)
{
//[0]传入两个非空的多项式
if ( (!(*La) || !(*La)->next) || (!(*Lb) || !(*Lb)->next))
{
printf("输入多项式不能为空!\n");
return;
}
//[1]初始化pa,pb分别指向La,Lb的首元结点,pc指向新链表的头结点
//pa用来遍历La中的所有结点
//pb用来遍历Lb中的所有结点
//pc用来遍历 新链表中 最新的有效结点
Node* pa, * pb, * pc;
pa = (*La)->next;
pb = (*Lb)->next;
(*Lc) = (*La);//用La的头结点作为新链表Lc的头结点(当然也可以使用Lb的头结点)
pc = (*Lc);//实际上pc指向的是La的头结点
//[2]遍历多项式 La 和 Lb,进行相加操作
while (pa && pb)
{
//<1>若两项指数相等------>进行系数相加操作
if (pa->expen == pb->expen)
{
double sum = pa->coef + pb->coef;
//<1.1>若系数相加结果为0,跳过并删除当前pa和pb所指向的结点(注意不需要更新pc的指向;因为pc指向的是新链表中 最新的有效结点)
if(sum==0)
{
//<1.1.1>临时生成两个指针,用来删除待销毁结点
Node* temp_pa = pa;
Node* temp_pb = pb;
//<1.1.2>跳过pa所指结点,并更新pa,pb指向下一个结点
pc->next = pa->next;
pa = pa->next;
pb = pb->next;
//<1.1.3>删除待销毁结点
free(temp_pa);
free(temp_pb);
}
//<1.2>若系数相加结果不为0,修改pa所指结点系数值,同时删除pb所指结点(注意需要更新pc的指向;因为pc指向的是新链表中 最新的有效结点)
else
{
//<1.2.1>临时生成1个指针,用来删除待销毁结点
Node* temp_pb = pb;
//<1.2.2>修改pa所指结点系数值,作为新的系数
pa->coef = sum;
//<1.2.3>修改新链表并保证完整性;同时修改pc的指向,指向最新的有效结点;更新pa,pb指向下一个结点
pc->next = pa;
pc = pa;
pa = pa->next;
pb = pb->next;
//<1.2.4>删除待销毁结点
free(temp_pb);
}
}
//<2>若pa指向的结点指数值 小于 pb指向的结点指数值,则将pa指向的结点添加到新链表中(类比升序链表的合并)
else if (pa->expen < pb->expen)
{
pc->next = pa;
pc = pa;
pa = pa->next;
}
//<3>若pa指向的结点指数值 大于等于 pb指向的结点指数值,则将pb指向的结点添加到新链表中(类比升序链表的合并)
else
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
//[3]将非空多项式的剩余结点添加到新链表中最后一个有效结点之后
pc->next = pa ? pa : pb;
free(*Lb);//释放Lb的头结点
}
//3.输出多项式
void printPolynomial(Polynomial L)
{
if (!L)
{
return -1;
}
Node* p = L->next;
while (p)
{
printf("(%lf*x)%d+ ", p->coef, p->expen);
p = p->next;
}
printf("end\n");
}
int main()
{
Polynomial L1, L2, L3;
CreatePolynomial(&L1, 3);
printPolynomial(L1);
CreatePolynomial(&L2, 4);
printPolynomial(L2);
addpolynomial(&L1, &L2, &L3);
printPolynomial(L3);
return 0;
}