【数据结构实验】C语言-一元二项式操作

简介: 【数据结构实验】C语言-一元二项式操作

1.实验目的

通过实验达到:


⑴ 理解和掌握线性结构的概念及其典型操作的算法思想;


⑵ 熟练掌握基本线性结构-线性表的顺序存储结构、链式存储结构及其操作的实现;


⑶ 理解和掌握受限线性结构——堆栈、队列、串、数组的概念及其典型操作的算法思想、实现。


2. 实验题目1-一元多项式的操作

实验题目:一元多项式的操作。


实验要求:设有两个一元多项式:


p(x)=p0+p1x+p2x2+•••+pnxn


q(x)=q0+q1x+q2x2+•••+qmxm


:多项式项的系数为实数,指数为整数,设计实现一元多项式操作的程序:


① 多项式链表建立:以(系数,指数)方式输入项建立多项式,返回所建立的链表的头结点;


② 多项式排序:将所建立的多项式按指数非递减(从小到大)进行排序;


③ 多项式相加:实现两个多项式相加操作。操作生成一个新的多项式,原有的两个多项式不变,返回生成的多项式的头指针;


④多项式的输出:按照p0+p1x+p2x2+•••+pnxn格式输出多项式;


⑤主函数通过调用多项式链表建立函数,输入两个多项式并分别输出;输出排序后的两个多项式;分别调用多项式相加函数实现多项式相加、相减操作,分别输出操作结果。


测试数据:两个多项式均不少于4项,并且需要有同类项,至少一个同类项系数相反。


2.1. 数据结构设计

定义的数据结构如下:


多项式节点结构体:

系数可以为小数

幂限制为整数

typedef struct Node {
  double coefficient;
  int power;
  struct Node* next;
}Node;


多项式链式存储结构体:

typedef struct {
  int size;
  Node* head;
}Multinomial;


2.2. 主要操作算法设计与分析

2.2.1. 多项式创建函数算法设计

void menu() {
  printf("---------------------------------\n");
  printf("本次插入遇到同类项,您要如何处理?\n");
  printf("1. 忽略本次输入\n");
  printf("2. 覆盖原项\n");
  printf("3. 系数相加\n");
  printf("---------------------------------\n");
}
void choice(Node* cur, double d) {
    //选择后续操作函数
}
void create(Multinomial* pm, double d, int power) {
    //多项式添加节点创建函数
}
void menu1() {
  printf("------------------\n");
  printf("0. 退出\n");
  printf("1. 输入多项式\n");
  printf("2. 输出多项式\n");
  printf("3. 排序多项式\n");
  printf("------------------\n");
}
void createMultinomial(Multinomial* list) {
  //一条多项式的创建函数
}



void createMultinomial(Multinomial* list);


返回类型:无返回值;


是否有参数:有, 传入二项式链表,对此二项式链表变量修改


步骤:


进入循环调用menu1函数, 选择对应操作

选择1添加一个节点

调用create方法,并在控制台输入系数和幂,成功添加一个二项式节点

若出现此幂数对应的二项式节点存在,调用chice函数

调用menu函数,选择忽略,覆盖,相加的其中一种操作

进行此操作直到选择0后退出,完成构造

算法时间复杂度:


由于二项式链表,没有一个成员代表链表的末尾,每次都应该遍历链表到末尾

所以时间复杂度为O(N);

2.2.2 二项式链表排序函数

Node* Sort(Node* head) {
    //二项式链表归并排序函数
}
void SortList(Multinomial* pm) {
  //二项式链表排序函数
}


void SortList(Multinomial* pm);


返回类型:无返回值;


是否有参数:有, 传入二项式链表,对此二项式链表变量修改


步骤:


节点的大小取决于幂的大小

调用Sort函数,Sort函数的返回值赋值给pm指向的head

进入Sort函数后,进行归并排序

利用快慢指针平分链表,并打断链表

将左右链表传入Sort函数,即进入递归

当传入Sort的链表为空链表或者一个节点的链表时,返回此链表

在递归中接受两个Sort函数返回值,并进行合并有序链表操作

返回合并链表后的大链表

算法时间复杂度:


归并排序时间复杂度:O(N * log2N)

2.2.3. 多项式输出函数

void display(Multinomial* pm) {
  //多项式输出函数
}

void display(Multinomial* pm);


返回类型:无返回值;


是否有参数:有, 传入二项式链表


步骤:


利用探路指针去遍历链表

对每一个节点进行分析并输出

系数为一或者负一应该省略1

幂为0应该省略x

幂小于0应该打括号

系数保留小数点后一位

系数小于0,二项式之间应该以减号分割,除非此二项式为首位

系数等于0,不显示

系数大于0, 位于首位不应该显示加号

最后打印回车

2.2.4. 多项式相加想减函数


void cre(Multinomial* pm, double d, int power) {
  //构造节点函数,为create函数的退化版本
}
void addition(Multinomial* pm1, Multinomial* pm2) {
  //多项式相加
}
void subtract(Multinomial* pm1, Multinomial* pm2) { // 【pm1 - pm2】左减右
  //多项式相减
}
void freeNode(Node* cur) {
  while (cur != NULL) {
  Node* tmp = cur;
  cur = cur->next;
  free(tmp);
  }
}

void addition(Multinomial* pm1, Multinomial* pm2);


void subtract(Multinomial* pm1, Multinomial* pm2);


返回类型:无返回值;


是否有参数:有, 传入两条二项式链表


对于多项式相加函数:


步骤:


将pm1与pm2两条链表的所有节点构造到一个新链表pm里

调用cre函数构造pm大链表

cre为create函数的退化,遇到同幂二项式,默认相加

排序pm二项式链表

输出pm二项式链表

调用freeNode函数释放pm链表

时间复杂度分析:O(N)


主要花费在构建pm链表上了


对于二项式链表相减函数,只需要在构建链表的时候,第二个二项式链表的节点的系数去相反数传入cre函数即可。


2.2.5. 主函数

void menu2() {
  printf("------------------------------------\n");
  printf("0. 退出\n");
  printf("1. 两个多项式相加\n");
  printf("2. 两个多项式相减(前面减后面)\n");
  printf("------------------------------------\n");
}
int main() {
  Multinomial list1 = { 0, NULL };
  Multinomial list2 = { 0, NULL };
  printf("输入第一个多项式\n");
  createMultinomial(&list1);
  printf("输入第二个多项式\n");
  createMultinomial(&list2);
  int input = 0;
  do {
  menu2();
  scanf("%d", &input);
  switch (input) {
  case 0:
    printf("退出成功\n");
    break;
  case 1:
    addition(&list1, &list2);
    break;
  case 2:
    subtract(&list1, &list2);
    break;
  default:
    printf("请重新输入\n");
    break;
  }
  } while (input);
  freeNode(list1.head);
  freeNode(list2.head);
  return 0;
}

步骤:


构造二项式链表1

在构建的过程中可以输出显示二项式全貌

在构造的过程中可以排序链表并输出排序后结果

构造二项式链表2

调用menu2菜单

选择相加或者相减操作

相加/相减后输出结果

选择0退出

调用freeNode函数释放两条链表

程序结束

2.3. 程序运行过程及结果

建立第一个二项式链表:

91edd1ff38fc4ad68c286a210757f214.png


建立第二个二项式链表:

550f0590adce4f8abb440ab9d9316eb3.png


相加相减二项式:


5cdd272540394a339da28aa9afd85805.png

3. 总结

在这个过程中遇到很多问题,例如空指针异常,结果与预计结果不符

但是只要好好调试,总是能解决问题

为了更加具有观赏性,优化输出

对于一些代码仍存在改进空间,可以再简洁!

例如利用函数指针数组减少switch的使用

4. 附录:源代码

4.1. 题目1 源代码:

4.1.1. basis.h头文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define INIT 10
typedef struct Node {
  double coefficient;
  int power;
  struct Node* next;
}Node;
typedef struct {
  int size;
  Node* head;
}Multinomial;
Node* Sort(Node* head);
void SortList(Multinomial* pm);
void display(Multinomial* pm);
void addition(Multinomial* pm1, Multinomial* pm2);
void subtract(Multinomial* pm1, Multinomial* pm2);
void createReplace(Multinomial* pm, double d, int power);
void createGiveUp(Multinomial* pm, double d, int power);
void cre(Multinomial* pm, double d, int power);
void create(Multinomial* pm, double d, int power);
void freeNode(Node* cur);


4.1.2. Create.c 源文件


#include "basis.h"
void menu() {
  printf("---------------------------------\n");
  printf("本次插入遇到同类项,您要如何处理?\n");
  printf("1. 忽略本次输入\n");
  printf("2. 覆盖原项\n");
  printf("3. 系数相加\n");
  printf("---------------------------------\n");
}
void choice(Node* cur, double d) {
  int input = 0;
  menu();
  scanf("%d", &input);
  switch (input) {
  case 1:
  break;
  case 2:
  cur->coefficient = d;
  break;
  case 3:
  cur->coefficient += d;
  break;
  default:
  printf("插入失败\n");
  break;
  }
}
void create(Multinomial* pm, double d, int power) {
  Node* newOne = (Node*)malloc(sizeof(Node));
  newOne->next = NULL;
  newOne->power = power;
  newOne->coefficient = d;
  Node* cur = pm->head;
  pm->size++;
  if (cur == NULL) {
  pm->head = newOne;
  return;
  }
  while (cur->next != NULL) {
  if (cur->power == power) {
    pm->size--;//要减掉
    choice(cur, d);
    return;
  }
  cur = cur->next;
  }
  if (cur->power == power) {
  pm->size--;//要减掉
  choice(cur, d);
  return;
  }
  else {
  cur->next = newOne;
  }
}
void cre(Multinomial* pm, double d, int power) {
  Node* newOne = (Node*)malloc(sizeof(Node));
  newOne->next = NULL;
  newOne->power = power;
  newOne->coefficient = d;
  Node* cur = pm->head;
  pm->size++;
  if (cur == NULL) {
  pm->head = newOne;
  return;
  }
  while (cur->next != NULL) {
  if (cur->power == power) {
    pm->size--;//要减掉
    cur->coefficient += d;
    return;
  }
  cur = cur->next;
  }
  if (cur->power == power) {
  pm->size--;//要减掉
  cur->coefficient += d;
  return;
  }
  else {
  cur->next = newOne;
  }
}

4.1.3. Print.c源文件


#include"basis.h"
void display(Multinomial* pm) {
  Node* cur = pm->head;
  while (cur != NULL) {
  int power = cur->power;
  double d = cur->coefficient;
  if (d == 0) {
    cur = cur->next;
    continue;
  }
  if (d == 1) {
    if (power == 0) {
    printf("1");
    }
    else {
    if (cur != pm->head) {
      printf("+");
    }
    goto again;
    }
  }
  if (d == -1) {
    if (pow == 0) {
    printf("-1");
    }
    else {
    printf("-");
    goto again;
    }
  }
  if (cur == pm->head) {
    printf("%.1lf", cur->coefficient);
  }
  else {
    if (d > 0) {
    printf("+%.1lf", cur->coefficient);
    }
    else if (d < 0) {
    printf("%.1lf", cur->coefficient);
    }
    else {
    cur = cur->next;
    continue;
    }
  }
  again:
  if (power != 0) {
    if (power != 1) {
    if (power < 0) {
      printf("x^(%d)", power);
    }
    else {
      printf("x^%d", power);
    }
    }
    else {
    printf("x");
    }
  }
  cur = cur->next;
  }
  printf("\n");
}
void addition(Multinomial* pm1, Multinomial* pm2) {
  Multinomial newOne = { 0, NULL };
  Node* cur1 = pm1->head;
  Node* cur2 = pm2->head;
  while (cur1 != NULL) {
  cre(&newOne, cur1->coefficient, cur1->power);
  cur1 = cur1->next;
  }
  while (cur2 != NULL) {
  cre(&newOne, cur2->coefficient, cur2->power);
  cur2 = cur2->next;
  }
  SortList(&newOne);
  printf("两式想加为:\n");
  display(&newOne);
  freeNode(newOne.head);
}
void subtract(Multinomial* pm1, Multinomial* pm2) { // 【pm1 - pm2】
  Multinomial newOne = { 0, NULL };
  Node* cur1 = pm1->head;
  Node* cur2 = pm2->head;
  while (cur1 != NULL) {
  cre(&newOne, cur1->coefficient, cur1->power);
  cur1 = cur1->next;
  }
  while (cur2 != NULL) {
  cre(&newOne, -1 * cur2->coefficient, cur2->power);
  cur2 = cur2->next;
  }
  SortList(&newOne);
  printf("两式想减为:\n");
  display(&newOne);
  freeNode(newOne.head);
}

4.1.4. Sort.c 源文件

#include "basis.h"
Node* Sort(Node* head) {
  if (head == NULL || head->next == NULL) {
  return head;
  }
  Node* slow = head;
  Node* fast = head->next;
  //找到中间位置~
  while (fast != NULL && fast->next != NULL) {
  slow = slow->next;
  fast = fast->next->next;
  }
  Node* tmp = slow->next;
  slow->next = NULL;
  Node* left = Sort(head);
  Node* right = Sort(tmp);
  Node* ph = (Node*)malloc(sizeof(Node));
  Node* cur = ph;
  while (left != NULL && right != NULL) {
  if (left->power < right->power) {
    cur->next = left;
    left = left->next;
  }
  else {
    cur->next = right;
    right = right->next;
  }
  cur = cur->next;
  }
  cur->next = left != NULL ? left : right;
  tmp = ph->next;
  free(ph);
  return tmp;
}
void SortList(Multinomial* pm) {
  pm->head = Sort(pm->head);
}

4.1.5. Test.c源文件(main函数所在)


#include "basis.h"
void menu1() {
  printf("------------------\n");
  printf("0. 退出\n");
  printf("1. 输入多项式\n");
  printf("2. 输出多项式\n");
  printf("3. 排序多项式\n");
  printf("------------------\n");
}
void menu2() {
  printf("------------------------------------\n");
  printf("0. 退出\n");
  printf("1. 两个多项式相加\n");
  printf("2. 两个多项式相减(前面减后面)\n");
  printf("------------------------------------\n");
}
void createMultinomial(Multinomial* list) {
  int input = 0;
  do {
  menu1();
  scanf("%d", &input);
  switch (input) {
  case 0:
    printf("退出成功\n");
    break;
  case 1:
    printf("注意:插入同类项,系数累加~\n");
    printf("请依次输入一个项的系数和幂:> ");
    int power = 0;
    double d = 0;
    scanf("%lf%d", &d, &power);
    create(list, d, power);
    break;
  case 2:
    printf("查看成功\n");
    display(list);
    break;
  case 3:
    printf("排序成功\n");
    SortList(list);
    display(list);
    break;
  default:
    printf("请重新输入\n");
  }
  } while (input);
}
int main() {
  Multinomial list1 = { 0, NULL };
  Multinomial list2 = { 0, NULL };
  printf("输入第一个多项式\n");
  createMultinomial(&list1);
  printf("输入第二个多项式\n");
  createMultinomial(&list2);
  int input = 0;
  do {
  menu2();
  scanf("%d", &input);
  switch (input) {
  case 0:
    printf("退出成功\n");
    break;
  case 1:
    addition(&list1, &list2);
    break;
  case 2:
    subtract(&list1, &list2);
    break;
  default:
    printf("请重新输入\n");
    break;
  }
  } while (input);
  freeNode(list1.head);
  freeNode(list2.head);
  return 0;
}
//free链表函数
void freeNode(Node* cur) {
  while (cur != NULL) {
  Node* tmp = cur;
  cur = cur->next;
  free(tmp);
  }
}


目录
相关文章
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
709 1
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
224 4
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
219 4
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
189 4
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
257 4
|
存储 算法 vr&ar
【趣学C语言和数据结构100例】71-75
本文介绍了五个C语言数据结构问题及其实现,涵盖链表与二叉树操作,包括按奇偶分解链表、交换二叉树左右子树、查找节点的双亲节点、计算二叉树深度及求最大关键值。通过递归和遍历等方法,解决了理论与实际应用中的常见问题,有助于提升编程能力和数据结构理解。
255 4
|
存储 算法 C语言
【趣学C语言和数据结构100例】66-70
本书《趣学C语言和数据结构100例》精选了5个典型的数据结构问题及C语言实现,涵盖链表与数组操作,如有序集合的集合运算、有序序列表的合并、数组中两顺序表位置互换、三递增序列公共元素查找及奇偶数重排。通过详细解析与代码示例,帮助读者深入理解数据结构与算法设计的核心思想,提升编程技能。
184 4
|
存储 算法 C语言
【趣学C语言和数据结构100例】51-55
本文介绍了五个关于链表操作的C语言实现案例,包括删除单链表中的重复元素、从两个有序链表中查找公共元素、判断一个链表是否为另一链表的连续子序列、判断循环双链表是否对称及合并两个循环单链表。每个案例都详细解析了算法思路与实现方法,涵盖了链表操作的多种场景,旨在帮助读者深入理解链表数据结构的应用,提升算法设计与编程能力。
232 4
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。