数据结构与算法 第二章习题课
一、一元多项式的加法与乘法运算
1. 多项式的表示
(1) 数据结构选型
- 重点在于如何表示非零项
数组 | 链表 | |
优点 | 编程简单,调试容易 | 可以动态添加节点 |
缺点 | 需要事先确定数组大小 MaxSize | 编程复杂,调试困难 |
- 结合本例,最好的实现方法是:动态数组
而下面将会通过链表实现
(2) 数据结构设计
struct PolyNode {int coef; // 表示项的系数int expon; // 表示项的指数Polynomial link; // 指向下一个结点
};
typedef struct PolyNode *Polynomial;
(3) 程序框架搭建
int main(void) {Polynomial P1, P2, PP, PS;/* 读入多项式1 */P1 = ReadPoly();/* 读入多项式2 */ P2 = ReadPoly();/* 乘法运算并输出 */PP = Mult(P1, P2);PrintPoly(PP);/* 加法运算并输出 */PS = Add(P1, P2);PrintPoly(PS);return 0;
}
- 需要设计的函数
- 构造新结点(多项式新的一项)
- 读一个多项式
- 两多项式相乘
- 两多项式相加
- 多项式输出
(4) 读入多项式
- 方法1:
Rear
的初值为NULL
- 先判断
Rear
的值。
若为NULL
,则用malloc
申请一个存储空间;
若不为NULL
,则直接在最后一项的后面添加新的一项
- 先判断
- 方法2:
Rear
指向一个空节点
下面采用方法2
/* 功能:设置多项式(读入多项式)* 输入:void* 输出:Polynomial P 设置的多项式的首地址*/
Polynomial ReadPoly() {Polynomial P, Rear, t;int N, c, e;/* 设置多项式的个数 N */scanf("%d", &N);/* 创建临时空结点 */P = (Polynomial)malloc(sizeof( struct PolyNode));P->link = NULL;Rear = P; // 更新结果多项式最后一项的地址/* 设置多项式中的各项 */while (N--) {scanf("%d %d", &c, &e); // 第一个参数是项的系数,第二个参数是项的指数Attach(c, e, &Rear); // 构造新结点,并加到 Rear 指向的结点(结果多项式的最后一项)的后面} /* 多项式各项创建好后,删除临时空结点 */t = P; // 用于空间释放P = P->link; // 删除临时空结点后,P 指向结果多项式第一项的首地址free(t); // 释放临时空结点return P; // 添加的新结点的首地址
}
(5) 构造新结点
/* 功能:构造新结点,并加到 Rear 指向的结点(结果多项式的最后一项)的后面* 输入:int c 新的一项的系数 * int e 新的一项的指数* Polynomial *pRear 指向结果多项式的最后一项。采用指针的指针,使对应的数据可以在自定义函数中改变(自定义函数是值传递)* 输出:void*/
void Attach(int c, int e, Polynomial *pRear) {Polynomial P;P = (Polynomial)malloc(sizeof( struct PolyNode));P->coef = c; // 为新的一项添加系数P->expon = e; // 为新的一项添加指数P->link = NULL; // 新的一项将位于结果多项式的末尾,后面没有其他项(*pRear)->link = P; // 在目前结果多项式最后一项的后面,添加新的一项*pRear = P; // 添加新的一项完成后,更新结果多项式最后一项的地址
}
(6) 两个多项式相加
/* 功能:两个多项式相加* 输入:Polynomial P1 * Polynomial P2 * 输出:Polynomial*/
Polynomial Add(Polynomial P1, Polynomial P2) {Polynomial t1, t2, Rear, P, t;t1 = P1;t2 = P2;/* 创建临时头结点(此节点没有系数和指数),利于后续操作。整个函数执行完后,要释放该临时头结点 */P = (Polynomial)malloc(sizeof (struct PolyNode));P->link = NULL;Rear = P;/* 在循环中实现两个多项式相加。若其中一个多项式遍历完毕,则退出循环,进行下一个操作 */while (t1 && t2) { // t1 与 t2 都是非空的结点,进入下面操作switch (Compare(t1->expon, t2->expon)) { /* Compare 是自定义函数,用于判断前后两个系数大小若 t1 指向的多项式系数大,则返回 1若 t1 指向的多项式系数小,则返回 -1若两个多项式系数相等,则返回 0 */case 1: {Attach(t1->coef, t1->expon, &Rear); // 将 t1 指向的多项式项,复制到结果多项式中 Rear 指向的项的后面t1 = t1->link; // 复制完成,P1后移break;}case 2: {Attach(t2->coef, t2->expon, &Rear); t2 = t2->link; break;}case 0: {sum = t1->coef + t2->coef; // 同类项系数相加if (sum) { // 若同类项系数相加的结果非0,即相加结果为非零项Attach(sum, t1->expon, &Rear); // 将相加结果形成新结点,并加到结果多项式中 Rear 指向的项后面}t1 = t1->link; // t1 后移t2 = t2->link;break;}}}/* 将未遍历完的另一个多项式的所有项一次复制到结果多项式中 Rear 指向的项后面 */while (t1) { // t2 指向的多项式处理完毕,t1 指向的多项式还有残余项Attach(t1->coef, t1->expon, &Rear);}while (t2) { // t1 指向的多项式处理完毕,t2 指向的多项式还有残余项Attach(t2->coef, t2->expon, &Rear);} /* 多项式各项创建好后,删除临时头结点 */t = P; // 用于空间释放P = P->link; // 删除临时空结点后,P 指向结果多项式第一项的首地址free(t); // 释放临时空结点return P; // 添加的新结点的首地址
}
(6) 两个多项式相乘
方法
- 方法1:将乘法运算转换为加法运算,即将
P1
当前项(ci, ei)
乘P2
多项式中的每一项,再加到结果多项式里。
/* P1 当前项 (ci, ei) 乘 P2 多项式中的每一项 */ t1 = P1; t2 = P2;// 创建空结点 P = (Polynomial)malloc(sizeof( struct PolyNode)); P->link = NULL; Rear = P;// 两个多项式相乘 while (t2) {Attach(t1->coef * t2->coef, t1->expon + t2->expon, &Rear);t2 = t2->link }
- 方法2:将
P1
当前项(c1i, e1i)
乘P2
当前项(c2i, e2i)
,并插入到结果多项式中。问题的关键是找到正确的插入位置
/* 功能:将两个多项式相乘* 输入:Polynomial P1 指向第一个多项式* Polynomial P2 指向第二个多项式* 输出:Polynomial P 结果多项式的第一项*/ Polynomial Mult(Polynomial P1, Polynomial P2) {Polynomial P, Rear, t1, t2, t;int c, e;if (!P1 || !P2) { // 若P1与P2指向的多项式中至少有一个是空的return NULL; // 退出本函数}t1 = P1; t2 = P2;P = (Polynomial)malloc(sizeof( struct PolyNode)); // 创建临时头结点P->link = NULL;Rear = P;while (t2) { // P1的第一项乘以P2的每一项,得到PAttach(t1->coef * t2->coef, t1->expon + t2->expon, &Rear); // 将乘积结果的每一项插到Rear指向的结果多项式的最后一项的后面t2 = t2->link;}t1 = t1->link;while (t1) {t2 = P2;Rear = P; // Rear指向结果多项式的第一项while (t2) { // 两个多项式中各项对应相乘e = t1->expon + t2->expon; // 计算当前的结果项c = t1->coef * t2->coef;while (Rear->link && Rear->link->expon > e) { // 若结果多项式的Rear的下一项存在,且系数大于当前的乘积结果的系数Rear = Rear->link; // Rear继续后移}// Rear下一项的系数小于等于乘积结果的系数if (Rear->link && Rear->link->expon == e) { // 若结果多项式的Rear下一项的系数等于当前乘积结果的系数,则这两项相加if (Rear->link->coef + c) { // 系数相加不等于零,则更新结果中的项的系数Rear->link->coef += c;} else { // 若系数相加等于零,则删除结果多项式中Rear后面的一项t = Rear->link;Rear->link = t->link;free(t);}} else { /* 若结果多项式的Rear下一项的系数小于当前乘积结果的系数,则将乘积结果插入到Rear的下一项,最终使乘积结果成为结果多项式的一项 */// 创建新结点t = (Polynomial)malloc(sizeof( struct PolyNode));t->coef = c;t->expon = e;t->link = Rear->link; // 新项的下一项是结果多项式中Rear的下一项Rear->link = t; // 结果多项式中Rear的下一项是新项Rear = Rear->link; // Rear移向下一项} t2 = t2->link;}t1 = t1->link;}// 删掉临时头结点t2 = P;P = P->link;free(t2);return P; }
- 方法1:将乘法运算转换为加法运算,即将
(7) 输出多项式
/* 功能:输出多项式* 输入:Polynomial P 要输出的多项式的项 * 输出:* 注意:打印格式为:系数1 指数1 系数2 指数2 ……*/
void PrintPoly(Polynomial P) {int flag = 0; // 用于调整输出格式if (!P) { // 若多项式为空,则输出对应的格式,并退出本函数printf("0 0\n");return;}while(P) {if (!flag) { // 若P是多项式第一项flag = 1; // 更新flag值} else { // 若P不是多项式第一项printf(" "); // 先打印空格}printf("%d %d", P->coef, P->expon); // 打印 系数 指数P = P->link; // 移向下一项}printf("\n"); // 输出完多项式的各项后,换行
}
二、逆转链表(Reversing Linked List)
将一个单向链表的前 kkk 个结点倒转顺序,与其余结点组成新链表,输出这个新链表
1. 单链表的逆转
原链表如下
插入临时头结点,便于操作
初始化指针 new
、 old
和 tmp
,new
指向逆转后的链表头结点,old
指向逆转前的链表头结点 ,tmp
指向逆转前的链表第二个结点
让第二个结点指向第一个结点
三个指针均往后移一个结点
指针 old
对应结点的下一个结点是 new
对应的结点
重复最近两次步骤,重复次数是 k
步,下图是结束重复之后的状态
修改指针指向,临时头结点的下一个是 new
对应的结点,第一个结点的下一个是 old
对应的结点
/* 功能:逆转单链表* 输入:Ptr head 包含临时头结点的单链表的首地址* int k 逆转前的链表中,前k个结点需要逆转* 输出:Ptr new 逆转后的单链表首地址* 注意:这是伪代码,只体现逻辑,不纠结具体细节*/
Ptr Reverse(Ptr head, int k) {/* 初始化new和old指针 */new = head->next;old = new->next;/* 循环操作 */int cnt = 1;while (cnt < k) {tmp = old->next; // 初始化 tmp ,tmp 始终在 old 对应的结点的后一个结点old->next = new; // 改变 old 周围的结点链接// new 和 old 整体往后移一个结点new = old; old = tmp;cnt++;}head->next->next = old; // 修改第一个结点的后面的链接return new;
}
2. 测试数据
- 在本例中,原链表中的前 kkk 个结点需要逆转,而剩下的结点保持原顺序。
- 边界测试
- 有时题干会规定地址的可用范围,如0000~9999,则测试数据也需要包含此范围的临界值
- 有时题干会设置链表总结点数满足 N=ak+bN=ak+bN=ak+b ,即这 NNN 个结点中,有 aaa 段长为 kkk 的结点集合,题干会要求在这几段中分别进行逆转,而剩下的 bbb 个结点不需要逆转。故测试数据时也要考虑这种情况
- 题干要求 k=Nk=Nk=N ,即整个链表都需要逆转,则测试数据需要做出相应调整
- 题干要求 k=1k=1k=1 ,即链表不需要逆转,则测试数据需要包含该情况
- 题干会在原链表中加入多余结点,如空结点,防止考生使用顺序结构的数据结构组织算法
数据结构与算法 第二章习题课相关推荐
- 数据结构与算法第二章 线性表、栈、队列、数组、字符串、树、二叉树、哈希表的增删查
03 增删查:掌握数据处理的基本操作,以不变应万变 通过前面课时的学习,相信你已经建立了利用数据结构去完成时空转移的思想.接下来,你需要在理论思想的指导下灵活使用.其实,要想灵活使用数据结构,你需要先 ...
- 数据结构与算法--第二章pro题解
文章目录 ==模板== --双链表 ==模板==--循环双链表 1.双链表的基本运算 2:整数双链表的基本运算-3 3:整数双链表的基本运算-4 4:循环双链表的基本运算 模板 --双链表 struc ...
- 计算机操作系统原理第二章习题
计算机操作系统原理第二章习题 1.什么是并发?什么是并行?用日常生活中的例子举例说明. 2.在操作系统中为什么要引入进程的概念?它会产生什么样的影响? 3.试说明PCB的作用具体表现在那些方面?为什么 ...
- 数据结构与算法 第二次实验报告堆栈队列
数据结构与算法 第二次实验报告 姓名:许恺 学号:2014011329 班级:计算机14-1 中国石油大学(北京)计算机科学与技术系 前 言 <数据结构>是计算机及相关 ...
- 自动驾驶决策规划算法第二章——Apollo EM Planner实践篇
前置学习内容:自动驾驶控制算法 [自动驾驶][零基础]基础自动驾驶控制算法笔记_免费教学录影带的博客-CSDN博客 自动驾驶决策规划第一章 自动驾驶决策规划算法第一章_免费教学录影带的博客-CSDN博 ...
- 用python编程、假设一年期定期利率_第二章-习题答案
第二章习题 1 . 写一个算法(流程图和 python 程序) :输入三个数,输出其最 大者. numA=3 numB=4 numC=5 if numA <= numB: if numC pri ...
- python可以在多种平台运行、体现了_2020年智慧树数据结构与算法第二单元章节测试答案...
2020年智慧树数据结构与算法第二单元章节测试答案 更多相关问题 为了寻找和选择通讯的报道对象,当你获知省教育招生考试院发布了<关于调整普通高等教育专科升本科考试录取办法的通知>后,应该熟 ...
- 统计学习导论:基于R应用——第二章习题
目前在看统计学习导论:基于R应用,觉得这本书非常适合入门,打算把课后习题全部做一遍,记录在此博客中. 第二章习题 1. (a) 当样本量n非常大,预测变量数p很小时,这样容易欠拟合,所以一个光滑度更高 ...
- java第二章选择题_Java第二章习题讲解(2)
第二章习题讲解(1) 3.阅读或调试程序 (1) 上机运行下列程序,注意观察输出的结果.Java public class E{ public static void main(String args ...
- Matlab第二章选择题填空题,matlab及其在大学物理中的应用第二章习题答案.doc
matlab及其在大学物理中的应用第二章习题答案.doc MATLAB及其在大学物理中的应用第二章习题答案作者荆楚理工吴世华21试求下列极限(1)(2)XX193LIM523LIMXXX ...
最新文章
- 一文速览机器学习的类别(Python代码)
- 统计学习方法第七章作业:SVM非线性支持向量机之SMO序列最小优化算法代码实现
- 河北计算机科学与技术研究生,2021年河北工业大学计算机科学与技术(081200)硕士研究生招生信息_考研招生计划和招生人数 - 学途吧...
- BZOJ3144: [Hnoi2013]切糕
- 原码一位乘法器设计_数字IC校招基础知识点复习(七)——超前进位加法器、Wallace树、Booth乘法器...
- php获取指定日期的万年历,分享3个php获取日历的函数
- 用python打印九九乘法表while_利用Python循环(包括whilefor)各种打印九九乘法表的实例...
- 为何学这么多技术,却做不好Coder!
- js版in_array函数
- html网页div是什么意思,HTML网页中div是什么意思?
- CodeWisdom软件供应链系列学术报告:第2期
- CS_2022_01
- 数论概论 第三章 勾股数组与单位圆
- python整数除法保留两位小数
- uniapp根据定位城市获取对应的天气
- 新冷战、通货膨胀与2009年亚洲金融危机爆发 (转)
- ASP源码:马克斯4.0内核的DM456动漫电影网站整站源码
- asp php主机空间域名注册
- 车载摄像头贵是道理的!它的规格真的不一般!
- 手机淘宝短视频业务「哇哦视频」迁移上 FaaS 笔记公开