【ZZULI数据结构实验一】多项式的三则运算

【ZZULI数据结构实验一】多项式的四则运算

  • ♋ 结构设计
  • ♋ 方法声明
  • ♋ 方法实现
    • 🐇 定义一个多项式类型并初始化---CreateDataList
    • 🐇 增加节点---Getnewnode
    • 🐇 打印多项式类型的数据-- PrintPoly
    • 🐇 单链表的尾插--Listpush_back
    • 🐇 多项式相加--PolyAdd
    • 🐇 多项式相减-- PolySub
    • 🐇 多项式相乘--PolyMult
    • 🐇 销毁单链表--Destroy
  • ♋ 测试

📃博客主页: 小镇敲码人
🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎
❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞

前言:本篇博客旨在个人学习,实现了多项式的加减乘运算,对代码的正确性不作100%的保证。

♋ 结构设计

这里我们使用带头单链表来存储多项式的数据(各项系数及其幂次),也可以用顺序表来存数据,但是这样头插不太方便,而且需要另外创建一个节点类型放一个项的系数和幂次。如果你对单链表还留有疑问,可以看看博主的这篇文章单链表详解
这个和下面的方法声明都放到头文件里。
在这里插入图片描述

typedef struct DataList
{int coe;//系数int power;//幂次struct DataList* next;
}List;

♋ 方法声明

List* CreateDataList();//输入数据并构造数据单链表的函数List* PolyAdd(List* A,List* B);//实现多项式相加List* PolySub(List* A,List* B);//实现多项式相减List* PolyMult(List* A,List* B);//实现多项式相乘List* Getnewnode(int coe_, int power_);//申请一个节点,并初始化void PrintPoly(List* A);//打印多项式void Listpush_back(List* C, int coe_,int power_);//尾插节点void Destroy(List* A);//销毁节点

♋ 方法实现

方法实现放到.c文件里。

在这里插入图片描述

🐇 定义一个多项式类型并初始化—CreateDataList

初始化就是放数据的过程,这里直接走一个循环,然后申请空间就可以了,如果你对申请空间有疑问,请看博主这篇文章C语言动态内存管理,这里我们规定输入数据时,应该先输入幂次大的节点(先输入系数,再输入幂次),然后下一次节点链接我们直接头插就可以保证多项式类型的节点从左到右是按照幂次升序存储的(方便后序的四则运算),单链表的头插比尾插简单(尾插需要找尾)

这里当然你也可以乱输入,增加一个排序函数就可以(按照幂次排)。小小实验我们并不需要这么麻烦,直接输入让它有序就可以了(dog。

这里我们选择带头的单链表,是为了避免头插时没有数据的判空。

代码实现:

List* CreateDataList()
{int coe_ = 0, power_ = 0;//初始化两个临时变量,用于输入每个节点的数据printf("请依次按照幂次从大到小输入数据,先输入多项式的系数,后输入幂次:\n");//提示信息List* Head = Getnewnode(-1, -1);//设置空的头节点while(scanf("%d%d", &coe_, &power_) != EOF){List* newnode = Getnewnode(coe_, power_);newnode->next = Head->next;Head->next = newnode;printf("请依次按照幂次从大到小输入数据,先输入多项式的系数,后输入幂次:\n");//提示信息,每次输入数据前都打印一次,这里会多打印一次无伤大雅} return Head;//返回头节点
}

🐇 增加节点—Getnewnode

我们在很多地方都需要申请节点,而且要初始化,为了不造成代码冗余,我们把其单独作为一个函数写出来,用的时候直接调用就好了。

代码实现:

List* Getnewnode(int coe_, int power_)
{List* newnode = (List*)malloc(sizeof(List));//在堆上申请空间if (newnode == NULL)//如果申请失败{printf("malloc Failed\n");exit(-1);}//初始化新节点newnode->coe = coe_;newnode->power = power_;newnode->next = NULL;//注意next要置空,否则会造成野指针的问题return newnode;//返回新节点
}

🐇 打印多项式类型的数据-- PrintPoly

这个函数就是单纯的打印,为了方便我们后序打印多项式类型看相加和相乘、以及相减的结果,当然你也可以通过调试查看。

代码实现:

void PrintPoly(List* A)//打印多项式
{assert(A);//防止A为空,我们不能对空解引用,assert函数相当于暴力检查List* cur = A->next;//从头节点的下一个节点开始遍历,因为头节点不存数据if (cur == NULL)//cur为空printf("多项式为空\n");while (cur != NULL)//cur不为空{if (cur->coe > 0 && cur != A->next)printf("+%d*(x^%d)", cur->coe, cur->power);elseprintf("%d*(x^%d)", cur->coe, cur->power);cur = cur->next;}printf("\n");
}

🐇 单链表的尾插–Listpush_back

在多项式相加的函数里面我们会用到单链表的尾插,如果你对其原理不太熟悉,请自行翻阅博主之前的博客。

代码实现:

void Listpush_back(List* C, int coe_, int power_)//尾插数据
{assert(C);//C不为空List* newnode = Getnewnode(coe_, power_);//申请新节点并初始化List* tail = C;while (tail->next)//找尾节点{tail = tail->next;}tail->next = newnode;//把新节点链接到尾节点的后面
}

🐇 多项式相加–PolyAdd

我们的多项式相加的思路类似双指针,O(N)时间复杂度内完成。

下面我们画图来分析一下这个过程:

在这里插入图片描述

  • 注意:这里为什么是尾插到C中呢?因为尾插才能保证C中数据是按幂次升序的,因为A和B中的数据都是按幂次升序排列的,我们为什么不把数据放到A和B中的其中一个呢,因为这样会改变A和B的内容,后面我们可能会对A、B做其它操作。

代码实现:

List* PolyAdd(List* A, List* B)
{assert(A && B);//断言,防止A或者B为空指针List* C = Getnewnode(-1, -1);//创建新的链表C,我们不希望改变链表A和B的值,所以把它们相加的结果存入C中List* curA = A->next;List* curB = B->next;while (curA && curB)//A和B的当前位置都不能为空{if (curA->power == curB->power)//如果当前幂次相等,A和B的系数相加,幂次不变,尾插到C中{int new_coe = curA->coe + curB->coe;if (new_coe != 0)Listpush_back(C, new_coe, curA->power);curA = curA->next;curB = curB->next;}else if (curA->power < curB->power)//如果B大,尾插curA{Listpush_back(C, curA->coe, curA->power);curA = curA->next;}else//否则尾插curB{Listpush_back(C, curB->coe, curB->power);curB = curB->next;}}//如果两个链表还有一个剩余,把剩下的数据尾插到C中while (curA){Listpush_back(C, curA->coe, curA->power);curA = curA->next;}while (curB){Listpush_back(C,curB->coe, curB->power);curB = curB->next;}return C;//返回相加的结果链表的头节点指针
}

🐇 多项式相减-- PolySub

多项式相减的大致思路都和多项式相加是一样的,有一个地方要注意,因为是A-B,当B中式子多时,A中对应项的系数就是0,要给B的系数加上负号。

代码实现:

// 定义PolySub函数,接受两个多项式链表A和B作为参数,返回相减后的多项式链表C  
List* PolySub(List* A, List* B)  
{  // 断言A和B都不为空,确保传入的多项式链表是有效的  assert(A && B);  // 创建一个新的链表C,并初始化其头节点(这里用-1作为占位符,实际使用中可能需要其他方式初始化)  List* C = Getnewnode(-1, -1);  // 初始化两个指向A和B链表中第一个实际节点的指针curA和curB  List* curA = A->next;  List* curB = B->next;  // 当curA和curB都不为空时,循环进行以下操作  while (curA && curB)  {  // 如果curA和curB指向的项的指数相同  if (curA->power == curB->power)  {  // 计算两个相同指数项的系数之差  int new_coe = curA->coe - curB->coe;  // 如果系数之差不为0,则将新的项(系数和指数)添加到C链表中  if (new_coe != 0)  Listpush_back(C, new_coe, curA->power);  // 移动curA和curB到下一个节点  curA = curA->next;  curB = curB->next;  }  // 如果curA指向的项的指数小于curB指向的项的指数  else if (curA->power < curB->power)  {  // 将curA指向的项(系数和指数)添加到C链表中  Listpush_back(C, curA->coe, curA->power);  // 移动curA到下一个节点  curA = curA->next;  }  // 否则(即curA指向的项的指数大于curB指向的项的指数)  else  {  // 将curB指向的项的相反数(系数取反,指数不变)添加到C链表中,实现减法  Listpush_back(C, -curB->coe, curB->power);  // 移动curB到下一个节点  curB = curB->next;  }  }  // 如果curA还有剩余节点(即A的某些项在B中没有对应项)  while (curA)  {  // 将这些项(系数和指数)添加到C链表中  Listpush_back(C, curA->coe, curA->power);  // 移动curA到下一个节点  curA = curA->next;  }  // 如果curB还有剩余节点(即B的某些项在A中没有对应项)  while (curB)  {  // 将这些项的相反数(系数取反,指数不变)添加到C链表中,实现减法  Listpush_back(C, -curB->coe, curB->power);  // 移动curB到下一个节点  curB = curB->next;  }  // 返回相减后的多项式链表C  return C;  
}

🐇 多项式相乘–PolyMult

相乘的思路是复用多项式相加的函数,先让B链表中的第一个项和A中各个项相乘(系数相乘,幂次相加),然后得到链表C,然后移动B继续和A中的各个相相乘,并执行多项式相加,最终得到结果。

代码实现:

// 定义PolyMult函数,接受两个多项式链表A和B作为参数,返回相乘后的多项式链表C  
List* PolyMult(List* A, List* B)  
{  // 断言A和B都不为空,确保传入的多项式链表是有效的  assert(A && B);  // 创建一个新的链表C,并初始化其头节点(这里用-1作为占位符)  List* C = Getnewnode(-1, -1);  // 初始化两个指针curA和curB,分别指向A和B链表中第一个实际节点  List* curA = A->next;  List* curB = B->next;  // 遍历curA指向的A链表中的每个项  while (curA)  {  // 计算当前curA指向的项与B链表中第一个项(curB指向的项)的乘积的系数和指数  int new_coe = (curA->coe) * (curB->coe);  int new_power = curA->power + curB->power;  // 将新的项(系数和指数)添加到C链表中  Listpush_back(C, new_coe, new_power);  // 移动curA到下一个节点  curA = curA->next;  }  // 初始化ans为NULL,用于存储最终的乘法结果  List* ans = NULL;  // 遍历curB指向的B链表中的每个项(从第二个项开始,因为第一个项已经在上面的循环中处理过了)  while (curB->next)  {  // 移动curB到下一个节点  curB = curB->next;  // 创建一个新的链表C1,用于存储当前curB指向的项与A链表中所有项的乘积结果  List* C1 = Getnewnode(-1, -1);  // 初始化curA,重新指向A链表中第一个实际节点  List* curA = A->next;  // 遍历curA指向的A链表中的每个项  while (curA)  {  // 计算当前curA指向的项与当前curB指向的项的乘积的系数和指数  int new_coe = (curA->coe) * (curB->coe);  int new_power = curA->power + curB->power;  // 将新的项(系数和指数)添加到C1链表中  Listpush_back(C1, new_coe, new_power);  // 移动curA到下一个节点  curA = curA->next;  }  // 将C链表和C1链表相加,得到当前curB指向的项与A链表相乘的结果,并更新ans  ans = PolyAdd(C, C1);  // 销毁C1链表,释放其占用的内存  Destroy(C1);  // 销毁C链表,释放其占用的内存(C现在保存的是上一轮的结果,我们不再需要它)  Destroy(C);  // 将ans赋值给C,准备进行下一轮的乘法运算  C = ans;  }  // 返回最终的乘法结果链表C  return C;  
}

这里由于我们的C1、和C链表每一次循环都会变成新的链表,我们要及时把旧的链表空间释放,防止内存泄漏的出现。

🐇 销毁单链表–Destroy

这里在多项式相乘函数里,会出现内存泄漏,我们需要及时回收空间,防止出现这种情况。

代码实现:

void Destroy(List* A)//销毁链表
{assert(A);List* cur = A;while (cur){List* cur_next = cur->next;//保存下一个节点的地址free(cur);//释放当前节点的空间cur = cur_next;//指针指向下一个节点}
}

♋ 测试

测试函数我们放到了main.c函数里,主要测试函数的各种功能是否和我们的预期一样,当然由于测试的数据有限,如有bug,欢迎指出。

#include"polynomial.h"void Test()
{List* A = CreateDataList();List* B = CreateDataList();List* AAddB = PolyAdd(A, B);List* ASubB = PolySub(A, B);List* AMultB = PolyMult(A, B);printf("多项式A: ");PrintPoly(A);printf("多项式B: ");PrintPoly(B);printf("多项式A+B: ");PrintPoly(AAddB);printf("多项式A-B: ");PrintPoly(ASubB);printf("多项式A*B: ");PrintPoly(AMultB);
}
int main()
{Test();return 0;
}

这里我们A输入:3 3 2 2 1 1
B输入: 4 4 3 3 2 2 1 1

运行结果:
在这里插入图片描述

和我们预期的结果一致。

这里我们A输入:1 5 1 3 1 1
B输入: 16 1 4 1 2

运行结果:

在这里插入图片描述
与预期结果一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/771186.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 优先级与结合性

运算优先级和结合性 表达式有多种运算符混合使用时&#xff0c;求解表达式的值&#xff0c;首先要解决各种运算符的运算优先次序问题。即&#xff0c;优先级和结合性。 例如&#xff1a;下面表达式的值取决于5种运算符的优先次序。 优先级是指不同级别运算符之间的运算次序&am…

卡行领航家用户端是怎么拼团怎么挣钱的?

#领航家代理政策/怎么代理/奖金制度/双2.0模式# 全国V&#xff1a;ok1234vip 领航家用户端&#xff1a;0.52费率 一次拼团0.44费率 两次拼团0.36费率 三次拼团0.2费率 ………… 十次拼团&#xff0c;客户每月挣20480 领航家代理端&#xff1a;无押激活返现高达166/台 分润万5-万…

vue 中实现下载后端返回的流式数据

验证是否是blob /*** Event 验证是否为blob格式* */export async function blobValidate(data) {try {const text await data.text();JSON.parse(text);return false;} catch (error) {return true;}}get请求 /*** Event: get请求下载后端返回的数据流* description: url[Stri…

Flutter 旋转动画 线性变化的旋转动画

直接上代码 图片自己添加一张就好了 import dart:math;import package:flutter/material.dart;import package:flutter/animation.dart;void main() > runApp(MyApp()); //旋转动画 class MyApp extends StatelessWidget {overrideWidget build(BuildContext context) {re…

ESCTF-逆向赛题WP

ESCTF_reverse题解 逆吧腻吧babypybabypolyreeasy_rere1你是个好孩子完结撒花 Q_W_Q 逆吧腻吧 下载副本后无壳&#xff0c;直接拖入ida分析分析函数逻辑&#xff1a;ida打开如下&#xff1a;提取出全局变量res的数据后&#xff0c;编写异或脚本进行解密&#xff1a; a[0xBF, …

Spring Task 知识点详解、案例、源代码解析

简介&#xff1a;Spring Task 定时任务   所谓定时任务。就是依据我们设定的时间定时运行任务&#xff0c;就像定时发邮件一样&#xff0c;设定时间到了。邮件就会自己主动发送。 在Spring大行其道的今天&#xff0c;Spring也提供了其定时任务功能&#xff0c;Spring Task。同…

3.3 数据定义 数据库与系统概论

目录 3.3.1 模式的定义与删除 1. 定义模式 2. 删除模式 CASCADE&#xff08;级联&#xff09; RESTRICT&#xff08;限制&#xff09; 3.3.2 基本表的定义、删除与修改 表的定义 2.数据类型 3. 模式与表 4. 修改基本表 5. 删除基本表 3.3.3 索引的建立与删除 1. …

力扣刷题44-46(力扣0062/0152/0198)

62. 不同路径 题目描述&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff0c;机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。问总共有多少条不同的路径&#xff1f; 思路&#xff1a; 其实就是问(0,0)->(m-1,n-1)一共有几条路。 第一个…

突破限制:亚信安慧AntDB高速处理能力的解密

AntDB不仅仅是一款优秀的数据库管理系统&#xff0c;更是一套提供丰富数据分析和处理工具的集合&#xff0c;它为用户提供了更多可能性&#xff0c;帮助他们深入理解数据、挖掘数据背后的价值。在当今信息爆炸的时代&#xff0c;数据已经成为企业决策的重要支撑&#xff0c;而A…

QT_day4:对话框

1、完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和密码不匹配&…

ubuntu下安装minconda

1.搜索清华源 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2.搜索conda 3.选一个合适自己的下载到本地 4.将下载的文件传入到ubuntu中 bash Miniconda3-py311_23.11.0-1-Linux-x86_64.sh 安装 5.source ~/.bashrc 激活即可&#xff08;必要步骤&#xff09;

Qt实现简易的多线程TCP服务器(附源码)

目录 一.UI界面的设计 二.服务器的启动 三.实现自定义的TcpServer类 1.在widget中声明自定义TcpServer类的成员变量 2.在TcpServer的构造函数中对于我们声明的m_widget进行初始化&#xff0c;m_widget我们用于后续的显示消息等&#xff0c;说白了就是主界面的更新显示等 …

[JVM]——垃圾回收

学习内容&#xff1a; GC、垃圾回收器、垃圾回收算法 目录 一、GC垃圾回收算法 1.1 可达性分析法 1.1.1 GC ROOT对象&#xff1a; 1.1.3 四种引用方式&#xff1a; ⭐小结&#xff1a; 1.2 其他回收算法 二、详解分代回收法&#xff1a; 三、垃圾回收器 3.1 串行垃圾…

人才测评,招聘视频制作影视设计师岗位的测评方案

常见的酷炫的视频&#xff0c;短视频&#xff0c;以及广告特效&#xff0c;年会中的各种片子&#xff0c;可以说各种各样的视觉盛宴&#xff0c;它们可都是出自影视后期的设计之手&#xff0c;尤其是当下短视频的兴起&#xff0c;抖音快速阿婆主&#xff0c;直播带货和主播&…

git笔记之撤销、回退、reset方面的笔记

git笔记之撤销、回退、reset方面的笔记 code review! 文章目录 git笔记之撤销、回退、reset方面的笔记1.git 已经commit了&#xff0c;还没push&#xff0c;如何撤销到初始状态git reset --soft HEAD~1git reset HEAD~1&#xff08;等同于 git reset --mixed HEAD~1&#xff0…

二十二、软考-系统架构设计师笔记-真题解析-2018年真题

软考-系统架构设计师-2018年上午选择题真题 考试时间 8:30 ~ 11:00 150分钟 1.在磁盘调度管理中&#xff0c;应先进行移臂调度&#xff0c;再进行旋转调度。假设磁盘移动臂位于21号柱面上&#xff0c;进程的请求序列如下表所示。如果采用最短移臂调度算法&#xff0c;那么系统…

详解Python面向对象编程(一)

类和对象 面向过程——怎么做&#xff1f; &#xff08;1&#xff09;把完成某一需求的所有步骤、从头到尾&#xff0c;逐步实现 &#xff08;2&#xff09;根据开发需求&#xff0c;将某些功能独立的代码块封装成一个又一个的函数 &#xff08;3&#xff09;最后完成的代码&a…

【Unity3D小功能】Unity3D中实现点击‘文字’出现‘UI面板’

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群&#xff1a;398291828 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 宠粉博主又来了&#xff0c;今天有粉丝问我如何实…

群晖NAS安装Video Station结合内网穿透实现公网访问本地影音文件

文章目录 1.使用环境要求&#xff1a;2.下载群晖videostation&#xff1a;3.公网访问本地群晖videostation中的电影&#xff1a;4.公网条件下使用电脑浏览器访问本地群晖video station5.公网条件下使用移动端&#xff08;搭载安卓&#xff0c;ios&#xff0c;ipados等系统的设备…

GitHub加速访问最简单的方法

Github是全球最大的代码开源平台&#xff0c;对于编程的小伙伴来说&#xff0c;这是一个巨大的宝库&#xff0c;也是编程学习的圣地。很对小伙伴在使用GitHub时会经常出现无法访问Github的情况。 一、解决方法——>修改hosts文件 通过 IP查询工具来获取当前Github网站的真实…