C语言练习(2)——链表实现多项式加法

C语言练习(2)——链表实现多项式加法,第1张

文章目录
  • 前言
  • 一、题目描述
  • 二、解题思路
  • 三、代码展示
    • 1.SL.h
      • (1)引用函数库
      • (2)定义链表
      • (3)声明接口函数
    • 2.SL.c
      • (1)创建带头单链表
      • (2)创建节点
      • (3)头插
      • (4)链表排序
      • (5)节点合并(合并同类项)
      • (6)链表求和
      • (7)链表打印
    • 3.test.c
  • 四、运行检验
  • 总结(求赞:kissing_heart:)


前言

兄弟们,每日一题,怡情悦兴
使用链表来实现多项式的加法。
这本该是数据结构中最为简单的试题,菜的抠脚的我敲了半个下午。。。😠
警醒:多练习!多思考! 切勿:走马观花,浅尝辄止!


一、题目描述

成对输入两个多项式的系数和指数,系数与指数间要空格,并且以0 0结束。
例如:1 2 3 4 5 2 3 4 0 0
这意味着输入了:
(为什么两个指数符号会变成这样😟😟😟)

二、解题思路

构建两个链表存放多项式,重点实现链表冒泡排序函数功能、合并同类项函数、多项式相加函数;
① 两个多项式分别按照指数由小到大排序
② 两个多项式分别合并同类项
③ 根据第一个多项式中的每一项,去第二个多项式中找同类项:
————❶如果有同类项,把系数累加并将该项移到和多项式中
————❷如果没有同类项,直接把该项移到和多项式中
④ 根据第二个多项式中的每一项,去第二个多项式中找同类项:
————❸如果有同类项,就不予理会,因为该项在上一部中已经被第一个多项式中的某一项累加过了
————❹如果没有同类项,就要把这一项移到和多项式中
字迹虽丑但清😉


三、代码展示

实现函数时:一定要注意某些控制循环的变量要 更新或者重新赋值
难点部分要仔细看注释!

1.SL.h (1)引用函数库

注意引用stdlib.h
有时你不引用,VS检查不出来,就会莫名其妙的报错
代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include

(2)定义链表

定义链表结构体时,分别命名List和Node,对节点和链表做出区分,更加直观。
此处也可以将 typedef int DataType;💣注意要加上分号
便于更改系数类型
代码如下

typedef struct ListNode
{
	int coef;
	int expon;
	struct ListNode* next;
}List,Node;
(3)声明接口函数

主要实现初始化函数、头插函数、打印函数等常见函数
以及特殊函数:链表冒泡排序、合并同类项、多项式相加
代码如下:

//创建带头单链表
void CreateList(List** PtrtoList);
//创建节点
Node* CreateNode(int coef, int expon);
//头插
void ListPushFront(List* PtrtoList);
//链表排序
void ListSort(List* PtrtoList);
//节点合并
List* NodeMerge(List* PtrtoList);
//链表求和
void ListAdd(List* p1, List* p2, List* add);
//链表打印
void ListPrint(List* PtrtoList);
2.SL.c (1)创建带头单链表

带头节点的链表一般都需要初始化函数,注意该处使用的是💣💣传址调用,要记得&
代码如下:

//创建带头单链表
void CreateList(List** PtrtoList)
{
	*PtrtoList = (List*)malloc(sizeof(List));
	(*PtrtoList)->coef = 0;
	(*PtrtoList)->expon = 0;
	(*PtrtoList)->next = NULL;
}
(2)创建节点

代码如下:

//创建节点
Node* CreateNode(int coef, int expon)
{
	Node* tem = (Node*)malloc(sizeof(Node));
	tem->coef = coef;
	tem->expon = expon;
	return tem;
}
(3)头插

💣💣💣要注意我们要获得键入的偶数个整数,每两个创建一个节点,且输入时只有到结尾0 0后才敲enter键,必须要这样使用scanf函数!
代码如下:

//头插
void ListPushFront(List* PtrtoList)
{
	int coef, expon;
	//注意scanf函数的使用形式
	scanf("%d %d", &coef, &expon);
	while (coef != 0 || expon != 0)
	{
		//输入0 0时停止循环
		Node* tem = CreateNode(coef, expon);
		tem->next = PtrtoList->next;
		PtrtoList->next = tem;
		scanf("%d %d", &coef, &expon);
	}
}
(4)链表排序

💣💣💣实现该功能的前提是要十分熟悉数组的冒泡排序,然后比葫芦画瓢,利用三个指针到达数组中i和j的循环控制功能。请仔细看注释!

代码如下:

//链表排序(冒泡)
void ListSort(List* PtrtoList)
{
	if (PtrtoList->next == NULL)
	{
		printf("链表为空\n");
		return;
	}
	//设立尾指针,通过将尾指针逐渐前移
	//实现控制每次冒泡排序的数据减少一个的功能
	Node* tail = NULL;
	Node* cur = NULL;
	Node* next = NULL;
	int flag = 1;
	//当尾指针指向第二项时,便停止
	//最后一趟排序只剩第一项数据,不必再排了
	while (tail!=PtrtoList->next->next)
	{
		cur = PtrtoList->next;
		next = cur->next;
		while (next != tail)
		{
			if (cur->expon > next->expon)
			{
				//交换系数和指数
				int tem1 = next->expon;
				next->expon = cur->expon;
				cur->expon = tem1;
				int tem2 = next->coef;
				next->coef = cur->coef;
				cur->coef = tem2;
				flag = 0;
			}
			cur = cur->next;
			next = cur->next;
		}
		if (flag == 1)
			break;
		//将尾指针前移
		tail = cur;
	}
}
(5)节点合并(合并同类项)

注意我写的这个函数是将链表合并后移到新链表中,最终返回List*类型
主要通过使用两个指针,前指针指向第一项,后指针指向第二项。后指针每循环遍历完一次,前指针后移一位,旗舰判断它们的指数,进行系数的累加。
💣💣💣仔细观察nexttem
💣💣💣 因为链表是排序后的,如果链表中有tem的同类项一定紧跟在其后,所以当nexttem的指数和tem不一样就直接break,并且在将该项移到新链表后,可以将nexttem直接赋给tem,不仅保证tem后移,还确保tem的指数一定增加了
代码如下:

//节点合并(合并多项式中的同类项)
List* NodeMerge(List* PtrtoList)
{
	//创建一个新链表,存放合并后的多项式
	List* NewList;
	CreateList(&NewList);
	//设立两个指针
	//第一个指针指向首元节点(第一项),然后向后遍历
	//第二个指针始终指向第一个指针的后面
	Node* tem = PtrtoList->next;
	Node* nexttem = tem->next;
	while (tem)
	{
		nexttem = tem->next;
		//记录第一项的系数
		int newcoef = tem->coef;
		//第二个指针向后移动
		while (nexttem)
		{
			//从第二个指针指向的位置向后
			//寻找和第一个指针指向的指数相同的项
			//累加它们的系数
			if (tem->expon != nexttem->expon)
			{
				break;
			}
			else
			{
				newcoef += nexttem->coef;
			}
			nexttem = nexttem->next;
		}
		//创建合并后的节点,头插到新链表中
		Node* new = CreateNode(newcoef, tem->expon);
		new->next = NewList->next;
		NewList->next = new;
		//更新tem指针,使得两个指针都向后移动
		tem = nexttem;
	}
	//返回新链表
	return NewList;
}
(6)链表求和

方法很值得记忆,这里再重复一遍,加强记忆!
⚠️ 根据第一个多项式中的每一项,去第二个多项式中找同类项:
————❶如果有同类项,把系数累加并将该项移到和多项式中
————❷如果没有同类项,直接把该项移到和多项式中
⚠️: 根据第二个多项式中的每一项,去第二个多项式中找同类项:
————❸如果有同类项,就不予理会,因为该项在上一部中已经被第一个多项式中的某一项累加过了
————❹如果没有同类项,就要把这一项移到和多项式中
仔细看代码
代码如下;

//链表求和
void ListAdd(List* PtrtoList1, List* PtrtoList2, List* add)
{
	//先将两个多项式分别合并同类项
	List* p1 = NodeMerge(PtrtoList1);
	List* p2 = NodeMerge(PtrtoList2);
	Node* tem1 = p1->next, * tem2 = p2->next;
	Node* tem3 = add->next;
	int newcoef = 0;
	//先依照第一个多项式,去第二个多项式中寻找同类项
	//如果有同类项,合并后移入和多项式中
	//如果没有同类项,将第一个多项式中的这一项移入和多项式中
	while (tem1)
	{
		//这里一定要注意重新赋值给tem2
		tem2 = p2->next;
		newcoef = tem1->coef;
		while (tem2)
		{
			//有同类项,合并,累加系数
			if (tem1->expon == tem2->expon)
			{
				newcoef += tem2->coef;
				//两个多项式已经被Merge过,只可能存在一个同类项
				break;
			}
			tem2 = tem2->next;
		}
		//将tem1中的项插入到和多项式中
		Node* new = CreateNode(newcoef, tem1->expon);
		new->next = add->next;
		add->next = new;
		tem1 = tem1->next;
	}
	//注意此tem2移动后变成了NULL,add后面也插入了新节点
	//tem2,tem3应该重新赋值
	tem2 = p2->next;
	tem3 = add->next;
	//依照第二个多项式,在和多项式中寻找同类项
	//有同类项的项不可以移到和多项式中
	//没有同类项的项可以移动
	while (tem2)
	{
		newcoef = tem2->coef;
		//注意tem3发生了改变,要重新赋值
		tem3 = add->next;
		//flag=1以为着没有同类项,即可以移动
		int flag = 1;
		while (tem3)
		{
			if (tem2->expon == tem3->expon)
			{
				flag = 0;
				break;
			}
			tem3 = tem3->next;
		}
		if (flag == 1)
		{
			Node* new = CreateNode(newcoef, tem2->expon);
			//将新找到的没有同类项的项移到和多项式中
			new->next = add->next;
			add->next = new;
		}
		tem2 = tem2->next;
	}
	//对和多项式排序
	ListSort(add);
}
(7)链表打印

常用接口函数,只要注意下这是带头节点的函数即可
只不过稍微有点麻烦,暂时没有优化😁😁
①分为最后一项和其他项(因为最后一项不用加+)
②再分为系数为0、系数为1、其它系数
③最后分成指数为0、指数为1、其它指数

//链表打印
void ListPrint(List* PtrtoList)
{
	printf("多项式之和是: ");
	Node* tem = PtrtoList->next;
	//除最后一项外,每项后面带有+
	while (tem->next)
	{
		//系数为0
		if (tem->coef == 0)
		{
			tem = tem->next;
		}
		//系数为1
		else if (tem->coef == 1)
		{
			//指数为0
			if (tem->expon == 0)
			{
				printf("1+");
				tem = tem->next;
			}
			//指数为1
			else if (tem->expon == 1)
			{
				printf("X+");
				tem = tem->next;
			}
			//指数不是1和0
			else
			{
				printf("X^%d+",tem->expon);
				tem = tem->next;
			}
		}
		//系数不是1和0
		else
		{
			//指数为0
			if (tem->expon == 0)
			{
				printf("%d+", tem->coef);
				tem = tem->next;

			}
			//指数为1
			else if(tem->expon==1)
			{
				printf("%dX+", tem->coef);
				tem = tem->next;
			}
			//指数不是1和0
			else
			{
				printf("%dX^%d+", tem->coef, tem->expon);
				tem = tem->next;
			}
		}
	}
	//最后一项不带+,单独打印
	//系数为0,不打印
	if (tem->coef == 0)
	{
		;
	}
	//系数为1
	else if (tem->coef == 1)
	{
		//指数为0
		if (tem->expon == 0)
		{
			printf("%d", tem->coef);
		}
		//指数为1
		else if (tem->expon == 1)
		{
			printf("X");
		}
		//指数不为1和0
		else
		{
			printf("X^%d",tem->expon);
		}
	}
	//系数不为1和0
	else
	{
		//指数为0
		if (tem->expon == 0)
		{
			printf("%d", tem->coef);
		}
		//指数为1
		else if (tem->expon == 1)
		{
			printf("%dX", tem->coef);
		}
		//指数不为0和1
		else
		{
			printf("%dX^%d", tem->coef, tem->expon);
		}
	}
}
3.test.c

这里稍微实现了一点菜单的提示功能
代码如下:

#include"sl.h"
int main()
{
	printf("请确保按照格式输入!\n");
	List *list1,*list2;
	CreateList(&list1);
	CreateList(&list2);
	//键入系数和指数
	printf("请两两输入系数和指数,系数与指数间有空格,并以0 0结尾!\n");
	printf("例:1 1 2 3 4 5 0 0\n");
	printf("请输入第一个多项式:");
	ListPushFront(list1);
	printf("请输入第二个多项式:");
	ListPushFront(list2);
	ListSort(list1);
	ListSort(list2);
	List* add;
	CreateList(&add);
	ListAdd(list1,list2,add);
	ListPrint(add);
}
四、运行检验

总结(求赞😘)

😑😑😑敲了半个下午的代码属实繁琐和笨拙,写的时候坚持正面硬钢,不参考大神们的优秀代码。写完后看别人的思路和代码,明白了差距的巨大,但这并不重要!

引用文本
重要的是:自己努力思考后,再去捧读优秀文章,颇有茅塞顿开、醍醐灌顶之感! 在这里希望大家都可以多独立实践,勤于深度思考,必有所获!

此外,最重要的是:拒绝白嫖哦

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/722789.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存