1. 一元多项式的运算
- 实现两个多项式加、减、乘运算。
- 将两个多项式存在数组里面,数组的下标就是每个系数的 x 的对应指数。
- 排完之后多项式相加就很简单了,相同下标的都是系数相同的,直接相加就行了。
- 用一个新的数组来存放相加之后的结果。
2. 稀疏多项式的运算
- 只将系数不为0的每一项的系数和指数存储起来。
- 线性表 P = ((p1,e1),(p2,e2),…(pm,em))。
- 把由系数和指数构成的序列就看成是一个线性表。
求这两个多项式的和:
线性表A = ((7,0),(3,1),(9,8),(5,17))
线性表B = ((8,1),(22,7),(-9,8))
- 创建一个新数组 C。
- 分别从头遍历比较 a 和 b 的每一项。
- 指数相同,对应系数相加,若其和不为0,则在c中增加一个新项。
- 指数不相同,则将指数交小的项复制到c中。
- 一个多项式已经遍历完毕时,将另一个剩余项依次复制到C中即可
稀疏多项式求和步骤
- 先把 A、B 两个数组的第一个元素的指数比较,A里面存的指数是0,比较小,先把 A 的第一个元素(7,0)存到C数组中,A 的第一项去掉不再参与计算。
- 将 A 的第二项(3,1)和 B 的第一项(8,1)的指数比较,指数都为1,则系数相加存入C,指数不变存入C,这两项去掉。
- 再将A的(9,8)和B的(22,7)比较,B 的指数比较小,将(22,7)存入 C 数组,然后去掉不再参与计算。
- 将 A 的(9,8)和 B 的(-9,8)比较,指数相同,则系数相加,系数相加为0,则这两项都删掉且不存入C数组。
- 多项式 B 已经遍历完成,则将 A 的剩余项复制到 C 即可。
数组C应该多大?
- 最多,线性表A和B的每一项的指数都不同,那么数组C就要7项。
- 最少,A和B每一项的指数都相同,且系数为相反数,那么结果就刚好是 0 项
- 给C的空间如果多了有可能浪费,少了就有可能放不下,这个时候就需要用到链式存储结构了。
顺序存储结构存在的问题
- 存储空间分配不灵活
- 运算的空间复杂度高
链式存储结构
- 不用数组来存储 A 和 B 的数据元素,不占用一块连续的空间,用链表的方式来存储,运算的时候需要多少就用多少空间。
结点定义
typedef struct PNode
{
float coef;//系数
int expn;//指数
struct PNode* next;//指针域
}PNode,*pplynomial;
- 一个多项式可以表示成由这些结点链接起来的单链表,要实现多项式的相加运算,优先需要创建多项式链表。
多项式创建
算法步骤
- 创建一个只有头结点的空链表。
- 根据多项式的项的个数 n,循环 n 次执行以下操作:
- 生成一个新结点 *s;
- 输入多项式当前项的系数和指数赋给新结点 *s 的数据域;
- 设置一个前趋指针 pre,用于指向待找到的第一个大于输入项指数的结点的前趋,pre 初始值指向头结点;
- 指针 p 初始化,指向首元结点;
- 循链向下逐个比较链表中当前结点与输入项指数,找到第一个大于输入项指数的结点 *q;
- 将输入项结点 *s 插入到结点 *q之前。
算法描述
//输入n项的系数和指数,建立表示多项式的有序链表p
void Createpolyn(polynoimal &P,int n)
{
p = new PNode;
p -> next = NULL;//先建立一个带头结点的单链表
for(i = 1;i <= n;i++)//依次输入n各非零项
{
s = new PNode;//生成新结点
cin >> s -> coef >> s -> expn;//输入系数和指数
pre = p;//pre用于保存p的前趋,初始值为头结点
q = p -> next;//q初始化,指向首元结点
//找到第一个大于输入项指针的项*q
while(q && q -> expn < s -> expn)
{
pre = q;
q = q -> next;
}
s -> next = q;//将输入项s插入到q和其前趋结点pre之间
pre -> next = s;
}
}
多项式的相加
- 比较两个链表的第一个结点,指数比较小的那个就作为新链表当中的元素,比较方法和用顺序表的没差别,两个结点的系数相加若是 0 则不管直接去看先一结点。
算法步骤
-
指针 p1 和 p2 初始化,分别指向 pa 和 pb 的首元结点。
-
p3 指向和多项式的当前结点,初值为 pa 的头结点。
-
当指针 p1 和 p2 均为到达相应表尾时,则循环比较 p1 和 p2 所指向结点对应的指数值(p1 -> expn 与 p2 -> expn),有下列三中情况:
- 当 p1 -> expn == p2 -> expn 时,则将两个结点中的系数相加:
- 若和不为零, 则修改 p1 所指向结点的系数值,同时删除 p2 所指向结点;
- 若和为零,则删除 p1 和 p2 所指向的结点;
- 当 p1 -> expn < p2 -> expn 时,则应摘取 p1 所指向结点插入到“和多项式”链表中去;
- 当 p1 -> expn > p2 -> expn 时,则应摘取 p2 所指向结点插入到“和多项式”链表中去。
- 当 p1 -> expn == p2 -> expn 时,则将两个结点中的系数相加:
-
将非空多项式的剩余段插入到 p3 所指向结点之后。
-
释放 pb 的头结点。
算法描述
//多项式加法:pa = pa+pb,利用两个多项式的结点构成“和多项式”
void Addpolyn(Polynomial &pa,polynomial &pb)
{
p1 = pa -> next;p2 = pb -> next;//p1和p2初始值分别指向pa和pb的首元结点
p3 = pa;//p3指向和多项式的当前结点,初始值为pa
while(p1 && p2)///p1和p2均非空
{
if(p1 -> expn == p2 -> expn)//指数相等
{
sum = p1 -> coef + p2 -> coef;//保存两项的系数和
if(sum)//系数和不为0
{
p1 -> coef = sum;//修改pa当前结点的系数值为两项系数的和
p3 -> next = p1;p3 = p1;//将修改后的pa当前结点链接在p3之后,让p3指向p1
p1 = pe -> next;//p1往后移动一位
r = p2;p2 = pe -> next;delete r;//删除pb当前结点,让p2往后移一位
}
else//系数和为0
{
r = p1;p1 = p1 -> next;delete r;//删除pa当前结点,p1指向后一项
r = p2;p2 = p2 -> next;delete r;//删除pb当前结点,p2指向后一项
}
}
else if(p1 -> expn < p2 -> expn)//pa当前结点的指数值小
{
p3 -> next = p1;//将p1链在p3之后
p3 = p1;//p3指向p1
p1 = p1 -> next;//p1指向后一项
}
else//pb当前结点的指数值小
{
p3 -> next = p2;//将p2连接在p3之后
p3 = p2;//让p3指向p2
p2 = p2 -> next;//让p2指向后一项
}
}
p3 -> next = p1?p1:p2;//插入非空多项式的剩余结点
delete pb;//释放pb的头结点
}
3. 图书信息管理系统
- 需要的功能:查找 、插入 、 删除 、修改 、排序 、计数
- 图书表可以抽象为线性表(顺序表或链表)。
- 表中每本图书抽象为线性表中的数据元素。
这个线性表可以用顺序表来实现,也可以用链表来实现。
- 如果表中的图书数目变化不大,很少做删除(插入)操作,那么就用顺序存储方式;
- 如果表中的图书数目变化大,经常要进行删除和插入操作,那么就用链式存储结构。
两种存储结构的结点类型定义