单链表实现多项式相加

2023-11-04

这个小项目用C语言实现
代码中有我的注释

思路:
用链表的每个节点存储表达式的每一项,因此每个链表就是一个表达式

链表节点类型的定义:

struct Node{
	DataType _elem; //项的系数
	Variate _ch;//常量和变量的标志(规定如果为'#',则该节点为常量项,否则为变量项,_ch为变量)
	int _power;//变量的次数(规定常量的次数只能为1)
};

相加逻辑:项类型相同并且系数相同的项可以相加,否则不能相加。eg:

exp1: 3x^3 + 1
exp2: 5x^3 + x^2 + 9
第一个表达式的3x^3和第二个表达式的5x^3可以相加,因为他们都含有变量,并且变量的系数相同。

所以,我们可以拿着依次拿着第一个链表中的节点去遍历第二个链表,在第二个链表中查找类型相同(即可以相加)的项,如果找到,则将两个节点(第一个链表中的当前节点和第二个节点中找到的目标节点)的系数相加并插入到新的链表(即相加后的新表达式):
在这里插入图片描述

如果在第二个链表中没有找到和链表1当前节点类型相同的节点,则将链表1的当前节点直接插入到新链表中:
在这里插入图片描述

当链表1已经走完了后(所有的节点都分别在链表2中查找过),此时得到的新表达式还不是最终的结果,因为有可能会有这种情况:
在这里插入图片描述

这种情况的处理办法是这样的,依次拿着第二个链表中的节点遍历新链表,只要是类型相同的,则说明已经添加过。反之,说明该节点还没有添加到新链表中。

有人可能会疑惑表达式的运算符如何存储?如何表示?

这里我是这样设计的:这个程序只是为了让我们熟悉链表这种数据结构,所以我从简考虑,只支持 + / - 两种运算符,那么就容易了,如果系数是正数,那么在打印表达式的时候,在该项前面打印一个 ‘+’;如果是系数是负数,那么不用打印,因为负数的符号就可以代表运算符了。具体操作可以参见代码,代码中我附上了注释。

代码:

//mylist.h
#pragma once

typedef int DataType;
typedef char Variate;


typedef struct Node{
  DataType _elem; //项的系数
  Variate _ch;  //规定'#'表示此项为常数项
  int _power; //项的次方
  struct Node* _next;
}Node, *PNode;

//初始化链表
void ListInit(PNode* head);
//添加节点
//--返回值说明--
//1 :成功
//0 :失败
int ListAdd(PNode* head, DataType elem, Variate ch, int Power);
//mylist.c
#include <stdio.h>
#include <assert.h>
#include "mylist.h"

//初始化链表
void ListInit(PNode* head){
  assert(head);
  *head = NULL;
}
//添加节点
int ListAdd(PNode* head, DataType elem, Variate ch, int Power){
  assert(head);
  if(NULL == *head){
    *head = (PNode)malloc(sizeof(Node));
    (*head)->_elem = elem;
    (*head)->_ch = ch;
    (*head)->_power = Power;
    (*head)->_next = NULL;
  }else{
    PNode tmp = *head;
    while(tmp->_next != NULL){
      tmp = tmp->_next;
    }
    tmp->_next = (PNode)malloc(sizeof(Node));
    tmp->_next->_elem = elem;
    tmp->_next->_ch = ch;
    tmp->_next->_power = Power;
    tmp->_next->_next = NULL;
  }
  return 1;
}
//main.c
#include <stdio.h>
#include "mylist.c"

/*
 * 1. 规定只能表达式只能计算 +/- 运算
 * 2. 规定常数项的次数只能是1
 */

void ExpressionPrint(PNode list){
  assert(list);
  PNode tmp = list;
  while(tmp != NULL){
  	//如果当前项系数大于零且不为表达式首项,打印加号(注意格式控制,加号前有空格)
    if(tmp->_elem > 0 && tmp != list){
      printf(" +");
    }
    //如果变量的次数不为1
    if(tmp->_ch != '#' && tmp->_power != 1){
      printf(" %d%c^%d", tmp->_elem, tmp->_ch, tmp->_power);
    }//如果变量的次数为1,则不打印该项变量的次数
    else if(tmp->_ch != '#' && tmp->_power == 1){
      printf(" %d%c", tmp->_elem, tmp->_ch);
    }//输出常量
    else if(tmp->_ch == '#'){
      printf(" %d", tmp->_elem);
    }
    tmp = tmp->_next;
  }//end while(tmp != NULL)
  printf("\n");
}

PNode ExpressionAdd(PNode list1, PNode list2){
  if(list1 == NULL){
    return list2;
  }
  if(list2 == NULL){
    return list1;
  }
  //拿着链表1中的项遍历链表2中的项
  PNode tmp1 = list1;
  PNode tmp2 = list2;
  PNode new_list;
  ListInit(&new_list);//一定不能忘记初始化链表!
  while(tmp1 != NULL){
    while(tmp2 != NULL){
      //如果链表1当前项和链表2项匹配,则将两者的系数相加并添加到新链表
      if(tmp1->_ch == tmp2->_ch && tmp1->_power == tmp2->_power){
        ListAdd(&new_list, tmp1->_elem + tmp2->_elem, 
        		tmp1->_ch, tmp1->_power);
        break;
      }
      tmp2 = tmp2->_next;
    }//end while(tmp2 != NULL)
    //如果没找到相同类型的项,则将链表1中的项添加到新链表中
    if(NULL == tmp2){
      ListAdd(&new_list, tmp1->_elem, tmp1->_ch, tmp1->_power);
    }//end while(tmp1 != NULL)
    tmp1 = tmp1->_next;//指向链表1的指针向后走
    tmp2 = list2;//让指向链表2的指针重新指向链表2的头部
  }
  PNode tmp3 = new_list;
  //将链表2中没有添加到新链表中的项找出来添加到新链表
  while(tmp2 != NULL){
    while(tmp3 != NULL){
      //如果在新链表中找到了相同类型的项,则退出循环
      if(tmp2->_ch == tmp3->_ch && tmp2->_power == tmp3->_power){
        break; 
      }
      tmp3 = tmp3->_next;
    }//end while(tmp3 != NULL)
    //如果在新链表中没有找到相同类型的项,则将链表2的当前项添加到新链表
    if(NULL == tmp3){
      ListAdd(&new_list, tmp2->_elem, tmp2->_ch, tmp2->_power);
    }
    tmp2 = tmp2->_next;
    tmp3 = new_list;//将指向新链表的指针重新指向新链表的头部
  }//end while(tmp2 != NULL)
  return new_list;
}

//测试用例
//由于我在实现的时候已经把一些特殊情况考虑到,所以这里的测试用例只是简单的
//看一下实现后的效果
int main() {
  PNode list_1;
  ListInit(&list_1);
  ListAdd(&list_1, 3, 'x', 29);
  ListAdd(&list_1, -2, 'x', 12);
  ListAdd(&list_1, 3, '#', 1);
  ExpressionPrint(list_1);
  PNode list_2;
  ListInit(&list_2);
  ListAdd(&list_2, 5, 'x', 29);
  ListAdd(&list_2, 4, 'x', 20);
  ListAdd(&list_2, 1, 'x', 2);
  ListAdd(&list_2, 12, '#', 1);
  ExpressionPrint(list_2);
  PNode result = ExpressionAdd(list_1, list_2);
  ExpressionPrint(result);
  return 0;
}

后记:这个程序在实现的过程中要考虑很多细节,这些细节由于我在写的时候就直接考虑了,所以并没有具体写出来,阅读这篇博客的朋友在自己实现的时候要考虑各种细节,具体可以比对我的代码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

单链表实现多项式相加 的相关文章

  • C++ 计算数组长度

    实现程序如下 include
  • Sublime Text3 BracketHighlighter

    BracketHighlighter 括号匹配插件 修改Preferences gt Package Settings gt BracketHighlighter gt Bracket Settings 修改settings User文件
  • 深入理解Gradle、Maven等JAVA项目的构建工具

    目录 简单概括构建工具的作用 构建工具的具体作用 Gradle和Maven的比较 简单概括构建工具的作用 构建工具用于自动化构建 编译 测试 和打包软件项目极大地简化软件开发的过程 提高开发效率和可靠性 让开发者更加专注于业务逻辑和代码实现
  • 云计算基本概念

    云计算的定义 1 云计算是同时描述一个系统平台或者一类应用程序的术语 云计算平台按需进行动态部署 Provision 部署 Configuration 重新部署 Reconfigure 以及取消服务 Deprovision 等 在云计算平台
  • Reducer buckets have been rebuilt in this iteration.

    在跑torch多GPU报错 Reducer buckets have been rebuilt in this iteration 原因是torch版本问题 torch1 7以上的distributed py发生更改导致报错 这玩意是dis

随机推荐

  • pymysql 重连

    self conn ping reconnect True
  • js给json格式的数组中每一项添加

    for let i 0 i lt this theme length i for let j 0 j lt dayarr length j this theme i day dayarr j
  • DevExpress GridControl复合表头(多行表头)设置

    首先 DevExpress XtraGrid的GridControl复合表头或多行表头的示例 界面如下图所示 实现步骤 1 将DevExpress的GridControl转换为BandedGridView 具体如下图 2 设置显示列及绑定的
  • SpringBoot 整合 kafka 遇到的版本不对应问题

    SpringBoot 整合 kafka 需要在SpringBoot项目里增加kafka的jar 而最为关键的一点是版本要对应好 如果你的SpringBoot是2 0 3版本
  • 国际版阿里云/腾讯云:弹性高性能计算E-HPC入门概述

    入门概述 本文介绍E HPC的运用流程 帮助您快速上手运用弹性高性能核算 下文以创立集群 在集群中安装GROMACS软件并运转水分子算例进行高性能核算为例 介绍弹性高性能核算的运用流程 帮助您快速上手运用弹性高性能核算 运用流程如下图所示
  • Jmeter —— 录制脚本

    1 第一步 添加http代理服务器 在测试计划 添加 非测试元件 http代理服务器 2 第二步 添加线程组 这个线程组是用来放录制的脚本 不添加也可以 就直接放在代理服务器下 测试计划 添加 线程 线程组 顺便讲一下线程组执行顺序 set
  • Idea快捷键(快速开发)

    Idea快捷键 快捷键 功能 Alt Enter 快速修复选择 Alt Insert 生成代码 如set get 构造方法等 Alt 切换到左侧视图 Alt 切换到右侧视图 Shift Shift 搜索文件 Ctrl D 复制当前一行 插入
  • CH8-排序

    文章目录 1 基本概念和排序方法概述 1 1 排序方法的分类 1 2 存储结构 顺序表 2 插入排序 2 1 插入排序的种类 直接插入 折半插入 希尔排序 3 交换排序 3 1 冒泡排序 3 2 快速排序 4 选择排序 4 1 直接排序 4
  • 【Spring Security】UserDetails 接口介绍

    文章目录 UserDetails 的作用 UserDetails 接口中各个方法详解 UserDetails 的作用 UserDetails 在 Spring Security 框架中主要担任获取用户信息的接口 通过该接口就能拿到用户的信息
  • Android Studio 优先源码编译的framework.jar(使用系统隐藏的api)

    引言 场景 做系统开发或者想使用隐藏的api时 通常只能使用反射的方式 缺点 需要使用的api或变量太多时不方便使用 解决办法 将需要在编译时使用的jar包参与编译 不编译到产品apk里 使app运行时调用的是系统api 步骤 每一步都必须
  • 【DirectX12】2.示例三角形绘制

    示例三角形绘制 1 效果 下面只贴出关于dx的代码 有时间再详细说明 2 标头 h pragma once include pch h include LVEDebug h include LVESystem h include
  • bootstrap点击删除按钮弹出确认框实现

  • orge工具

    tortoisehg 3 2 1 x64 msi mercurial 3 2 1 x64 msi
  • 微信支付宝大规模补贴抢占刷脸支付入口

    刷脸支付相较于二维码 优势在于去掉了手机这一介质 但介质的缺失 也意味着人脸信息的泄露变得更加容易 刷脸支付的基本原理就是将终端硬件采集到的信息与云端的存储的信息进行比对 看信息是否一致 然后解锁完成人脸支付 如果云端生物数据库发生信息泄露
  • 【华为OD统一考试A卷

    华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一修改为OD统一考试 A卷 和OD统一考试 B卷 你收到的链接上面会标注A卷还是B卷 请注意 根据反馈 目前大部分收到的都是
  • 微信小程序设置允许转发分享onShareAppMessage(Object object)

    在需要分享的页面js文件中写 Page onShareAppMessage const promise new Promise resolve gt setTimeout gt resolve title 自定义转发标题 2000 retu
  • 基于概率论的分类方法:朴素贝叶斯

    需要分类器做出分类决策 可以使分类器给出各个类别的概率估计值 然后选择概率最高的作为其的类别 在这里使用到了概率论中的贝叶斯公式 P A B P A P B A P B 其中P A B 是后验概率 P A 是先验概率 P B A P B 为
  • Python数据分析与展示第三课

    Matplotlib是python优秀的数据可视化第三方库 数据可视化 将数据以特定的图形图像的形式展现出来 Matplotlib由各种可视化的类构成的 使用方式 import matplotlib pyplot as plt as plt
  • 论文收录引用证明常见问题汇总

    学术论文在毕业 评职称 保研 考博 留学等方面均有重要意义 因此往往需要开具检索证明 然而 开具检索证明的前提是论文必须被收录 1 什么是论文收录引用证明 论文收录引用证明是用来证明作者在科研领域中的实力和成就 当用户需要查询其论文在指定数
  • 单链表实现多项式相加

    这个小项目用C语言实现 代码中有我的注释 思路 用链表的每个节点存储表达式的每一项 因此每个链表就是一个表达式 链表节点类型的定义 struct Node DataType elem 项的系数 Variate ch 常量和变量的标志 规定如