数据结构-线性表的应用

目录

  • 前言
  • 一、有序表的合并
    • 1.1 顺序表实现
    • 1.2 单链表实现
  • 二、稀疏多项式的相加和相乘
    • 2.1 稀疏多项式的相加
    • 2.2 稀疏多项式的相乘
  • 总结

前言

本篇文章介绍线性表的应用,分别使用顺序表和单链表实现有序表的合并,最后介绍如何使用单链表实现两个稀疏多项式的相加和相乘。

一、有序表的合并

已知线性表La和Lb的数据元素按值非递减有序排列,现要求将La和Lb合并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排序。
非递减指可以有相同的值出现在同一个线性表中
L a = ( a , b , c ) La=(a,b,c) La=(a,b,c)
L b = ( c , d , e , f ) Lb=(c,d,e,f) Lb=(c,d,e,f)
L a La La L b Lb Lb合并后
L c = ( a , b , c , c , d , e , f ) Lc=(a,b,c,c,d,e,f) Lc=(a,b,c,c,d,e,f)

1.1 顺序表实现

算法步骤

  1. 创建一个空表Lc
  2. 依次从La或Lb中摘取元素值较小的结点插入到Lc表后,直至其中一个表变为空为止
  3. 继续将La或Lb其中一个表的剩余结点插图到Lc表的最后

代码实现如下

//定义返回值状态码
#define SUCCESS 1
#define ERROR   0

//这里假设元素的数据类型为char
typedef char ElemType;


//定义一个线性表
struct SeqList {
	int MAXNUM;			//线性表中最大元素的个数
	int n;				//线性表中实际的元素个数,n <= MAXNUM
	ElemType* element;	//存放线性表元素,element[0],element[1]...element[n-1]
};

//定义一个SeqList的指针类型
typedef struct SeqList* PSeqList;
//合并两个有序表
void mergeList_seq(PSeqList La, PSeqList Lb, PSeqList Lc)
{
	ElemType* pa = La->element;
	ElemType* pb = Lb->element;  //指针pa和pb分别指向两个表的第一个元素
	Lc->n = La->n + Lb->n;
	Lc->MAXNUM = Lc->n;
	Lc->element = (ElemType*)malloc(sizeof(Lc->n)); //为合并的新表分配一个数组空间
	if (NULL == Lc->element)
	{
		printf("malloc fail!\n");
		exit(ERROR);
	}
	ElemType* pc = Lc->element;   //指针pc指向Lc表的第一个元素
	ElemType* pa_last = La->element + (La->n - 1); //指针pa_last指向La表的最后一个元素
	ElemType* pb_last = Lb->element + (Lb->n - 1); //指针pb_last指向Lb表的最后一个元素

	while (pa <= pa_last && pb <= pb_last)
	{
		if (*pa <= *pb)
			*pc++ = *pa++;
		else
			*pc++ = *pb++;
	}
	while (pa <= pa_last) *pc++ = *pa++; //Lb表到达表尾,将La表中剩余元素加入Lc
	while (pb <= pb_last) *pc++ = *pb++; //La表到达表尾,将Lb表中剩余元素加入Lc
}

1.2 单链表实现

为了方便使用,选择带头结点的单链表

算法步骤

  1. pa和pb指针分别指向La和Lb的首元结点
  2. pc指向La的头结点,用La的头结点作为Lc的头结点
  3. 依次从La或Lb中摘取元素值较小的结点插入到Lc表后,直至其中一个表变为空为止
  4. 继续将La或Lb其中一个表的剩余结点插图到Lc表的最后

代码实现如下

//假设数据元素类型为char
typedef char ElemType;

//定义结点类型
struct Node;				  	
typedef struct Node* PNode;   //假设作为结点指针类型
struct Node {
	ElemType data;   //数据域
	PNode next;		//指针域
};

typedef struct Node* LinkList;  //假设作为单链表类型


//合并两个有序表
//带头结点
void mergeList_link(LinkList* La, LinkList* Lb, LinkList* Lc)
{
	PNode pa = (*La)->next;
	PNode pb = (*Lb)->next;
	PNode pc = *La;
	*Lc = *La;      //用La的头结点作为Lc的头结点
	while (pa && pb)
	{
		if (pa->data <= pb->data)
		{
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}
		else
		{
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	}
	pc->next = pa ? pa : pb;  //插入剩余元素
	free(*Lb);				//释放Lb的头结点
	*Lb = NULL;
}

二、稀疏多项式的相加和相乘

假设有两个多项式
f 1 ( x ) = 7 + 3 x + 9 x 8 + 5 x 17 f_1(x)=7+3x+9x^8+5x^{17} f1(x)=7+3x+9x8+5x17
f 2 ( x ) = 8 x + 22 x 7 − 9 x 8 f_2(x)=8x+22x^7-9x^8 f2(x)=8x+22x79x8
多项式的通项公式为
P n ( x ) = p 1 x e 1 + p 2 x e 2 + ⋯ + p m x e m P_n(x)=p_1x^{e_1}+p_2x^{e_2}+\cdots+p_mx^{e_m} Pn(x)=p1xe1+p2xe2++pmxem
利用线性表P表示,则
线性表 P = ( ( p 1 , e 1 ) , ( p 2 , e 2 ) , ⋯   , ( p m , e m ) ) 线性表P=((p_1,e_1),(p_2,e_2),\cdots,(p_m,e_m)) 线性表P=((p1,e1),(p2,e2),,(pm,em))
f 1 ( x ) 和 f 2 ( x ) 分别用线性表 A 和 B 表示 f_1(x)和f_2(x)分别用线性表A和B表示 f1(x)f2(x)分别用线性表AB表示
线性表 A = ( ( 7 , 0 ) , ( 3 , 1 ) , ( 9 , 8 ) , ( 5 , 17 ) ) 线性表A=((7,0),(3,1),(9,8),(5,17)) 线性表A=((7,0),(3,1),(9,8),(5,17))
线性表 B = ( ( 8 , 1 ) , ( 22 , 7 ) , ( − 9 , 8 ) ) 线性表B=((8,1),(22,7),(-9,8)) 线性表B=((8,1),(22,7),(9,8))
假设使用顺序表实现多项式的相加

算法步骤

  1. 创建一个新数组c
  2. 分别从头遍历比较a和b的每一项
    指数相同,对应系数相加,若其和为零,则比较两个表的下一项,若其和不为零,则在c中增加一个新项
    指数不相同,则将指数比较小的项复制到c中
  3. 一个多项式遍历完毕时,将另一个剩余项依次复制到c中

那么,数组c的大小如何确定?由于无法确定数组c的大小,所以这里不使用顺序表实现,而是用单链表实现。
定义多项式的结点及其结构

//定义多项式结点
struct PolyNode
{
	float coef; //系数
	int   expn; //指数
	struct PolyNode* next;
};
//定义多项式结点指针类型
typedef struct PolyNode* PPolyNode;
//定义多项式类型
typedef struct PolyNode* PolyLinkList;

2.1 稀疏多项式的相加

算法步骤:

  1. 指针p1和p2初始化,分别指向Pa和Pb的首元结点
  2. p3指向和多项式的当前结点,初值为Pa的头结点
  3. 当指针p1和p2均为到达表尾时,则循环比较p1和p2所指结点的指数值
  4. p1->expn 与 p2->expn分3种情况:
    当p1->expn == p2->expn是,则将两个结点中的系数相加
    若和不为零,则修改p1所指结点的系数值,同时删除p2所指结点
    若和为零,则删除p1和p2所指结点
    当p1->expn < p2->expn时,则取p1所指结点插入到和多项式链表中
    当p1->expn > p2->expn时,则取p2所指结点插入到和多项式链表中
  5. 将非空表的剩余结点插入到p3所指结点的后面
  6. 释放Pb的头结点

代码实现如下

void poly_add(PolyLinkList* Pa, PolyLinkList* Pb, PolyLinkList* Pc)
{
	PPolyNode p1 = (*Pa)->next;    //指向Pa链表的首元结点
	PPolyNode p2 = (*Pb)->next;    //指向Pb链表的首元结点
	PPolyNode p3 = *Pa;			  //指向Pa的头结点,作为和多项式链表	
	*Pc = *Pa;
	PPolyNode q = NULL;		     //指向要被删除的结点		

	while (p1 && p2)
	{
		if (p1->expn == p2->expn)		//p1指数等于p2指数
		{
			float coef = p1->coef + p2->coef;
			if (coef)		//不为零
			{
				//修改p1所指结点的系数
				p1->coef = coef;
				p3->next = p1;
				p3 = p1;
				p1 = p1->next;
			}
			else          //为零
			{
				//删除p1所指结点
				q = p1;
				p1 = p1->next;
				free(q);
				q = NULL;

			}

			//删除p2所指结点
			q = p2;
			p2 = p2->next;
			free(q);
			q = NULL;

		}  
		else if (p1->expn < p2->expn)		//p1指数小于p2指数
		{
			//p1所指结点插入到和多项式链表
			p3->next = p1;
			p3 = p1;
			p1 = p1->next;
		}
		else                              //p1指数大于p2指数
		{
			//p2所指结点插入到和多项式链表
			p3->next = p2;
			p3 = p2;
			p2 = p2->next;
		}

	}
	p3->next = p1 ? p1 : p2;	//插入剩余数据元素
	free(*Pb);		//释放Pb头结点
	*Pb = NULL;
}

2.2 稀疏多项式的相乘

  1. 指针p1和p2初始化,分别指向Pa和Pb的首元结点
  2. 指针p3初始化,指向Pc的头结点,初化始时,Pc只是一个空表
  3. 用Pa的第一项与Pb的每一项相乘,将每一项相乘结果插入到Pc中(有序)
  4. 从Pa的第二项开始与Pb的每一项相乘,将每一项结果插入到Pc中(插入后有序)
    在Pc寻找插入位置
    设coef = p1->coef * p2->coef ,expn = p1->expn + p2->expn,表示当前p1和p2所指项的相乘结果
    若p3->next->expn < expn,则p3 = p3->next,直到p3->next->expn > expn,分两种情况
    若存在p3->next->expn > expn, 则新建一个结点插入到p3所指结点后
    若不存在p3->next->expn > expn,即p3->next == NULL时,则新建一个结点插入到p3所指结>点后
    若p3->next->expn == expn,分两种情况
    若p3->next->coef + coef结果为零,则删除p3->next所指结点
    若p3->next->coef + coef结果不为零,则修改p3->next所指结点的系数

代码实现如下

//逐项插入法
void poly_mul(PolyLinkList* Pa, PolyLinkList* Pb, PolyLinkList* Pc)
{
	PPolyNode p1 = (*Pa)->next;
	PPolyNode p2 = (*Pb)->next;   //p1,p2分别指向Pa和Pb的首元结点
	PPolyNode p3 = *Pc;			  //p3分别指向Pc的头结点	
	PPolyNode temp = NULL;		  //作为一个临时的结点指针

	if (p1)//将p1的第一项乘以Pb的每一项
	{
		while (p2)
		{
			PPolyNode newNode = (PPolyNode)malloc(sizeof(struct PolyNode));
			if (NULL == newNode)
			{
				printf("malloc fail!\n");
				exit(ERROR);
			}
			newNode->coef = p1->coef * p2->coef;  //p1,p2所指结点的系数相乘
			newNode->expn = p1->expn + p2->expn; //p1,p2所指结点的指数相加
			newNode->next = NULL;
			p3->next = newNode;
			p3 = newNode;
			p2 = p2->next;
		}
	}
	//从Pa的第二项开始与Pb的每一项相乘,将每一项结果插入到Pc,直到p1到达Pa的表尾
	p1 = p1->next;
	while (p1)
	{
		p2 = (*Pb)->next;
		p3 = *Pc;
		while (p2)
		{
			//在Pc寻找插入位置
			float coef = p1->coef * p2->coef;
			int   expn = p1->expn + p2->expn;
			while (p3->next && p3->next->expn < expn)
				p3 = p3->next;
			if (p3->next && p3->next->expn == expn)   //expn与p3->next->expn相同
			{
				if (p3->next->coef + coef)	//和不为零
					p3->next->coef += coef;
				else    //和为零
				{
						//删除p3->next所指结点
					temp = p3->next;
					p3->next = temp->next;
					free(temp);
					temp = NULL;
				}
			}
			else   //p3->next->expn > expn 或p3->next == NULL
			{
				//在p3->next前插入一个新结点
				temp = (PPolyNode)malloc(sizeof(struct PolyNode));
				if (NULL == temp)
				{
					printf("malloc fail!\n");
					destoryPoly(Pc);
				}
				temp->coef = coef;
				temp->expn = expn;
				temp->next = p3->next;
				p3->next = temp;
				p3 = p3->next;
			}
			p2 = p2->next;
		}
		p1 = p1->next;
	}
}

总结

完整代码:https://gitee.com/PYSpring/data-structure/tree/master

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【java高级】【算法】通过子节点 反向获取 树路径父节点 且不获取无关节点

有一个奇葩需求 要求 用户配置在某选择框的选项 例如 然后在选择时显示 用户配置的选项 依旧是返回树,但是只包含 选择的子节点。 以及涉及的父节点,树路径 不返回无关节点 【一般】我们开发中都是直接通过 树节点 返回 其下子节点 这个需求的确很奇葩。 而且还要考…

语音大模型引领自然交互新时代,景联文科技推出高质量语音大模型数据库

近期&#xff0c;OpenAI正式发布语音大模型GPT-4o&#xff0c;可以综合利用语音、文本和视觉信息进行推理&#xff0c;扮演一个个人语音交互助手。 在音频处理方面&#xff0c;它不仅能识别和转录多种口音和方言&#xff0c;改变语音的速度音调和振动&#xff0c;还能进行声音模…

CAS(compare and swap)

文章目录 CAS 的应用标准库的原子类自旋锁 CAS的ABA问题什么是 ABA 问题ABA 问题引来的 BUG相关面试题 CAS是一条CPU指令,就可以完成比较和交换这样的操作 我们假设内存中的原数据V&#xff0c;旧的预期值A&#xff0c;需要修改的新值B。 1.比较 A 与 V 是否相等。&#xff08;…

2024年7月4日 (周四) 叶子游戏新闻

老板键工具来唤去: 它可以为常用程序自定义快捷键&#xff0c;实现一键唤起、一键隐藏的 Windows 工具&#xff0c;并且支持窗口动态绑定快捷键&#xff08;无需设置自动实现&#xff09;。 卸载工具 HiBitUninstaller: Windows上的软件卸载工具 《最终幻想14》画面升级后 著名…

【高级篇】第10章 Elasticsearch 集群管理与扩展

在本章中,我们将深入探讨Elasticsearch集群的管理与扩展策略,旨在帮助读者构建一个既能应对大规模数据处理需求,又能保持高可用性和弹性的系统架构。我们将从集群架构设计入手,解析不同节点的角色与配置,然后转向节点发现与配置同步机制,最后讨论水平扩展与容错策略,确保…

【Python实战因果推断】20_线性回归的不合理效果10

目录 Neutral Controls Noise Inducing Control Feature Selection: A Bias-Variance Trade-Off Neutral Controls 现在&#xff0c;您可能已经对回归如何调整混杂变量有了一定的了解。如果您想知道干预 T 对 Y 的影响&#xff0c;同时调整混杂变量 X&#xff0c;您所要做的…

系统提示我未定义与 ‘double‘ 类型的输入参数相对应的函数 ‘finverse‘,如何解决?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

新火种AI|AI搜索挑战百度谷歌,重塑信息检索的市场?

作者&#xff1a;一号 编辑&#xff1a;美美 AI正在颠覆传统的搜索引擎市场。 随着ChatGPT等大型语言模型的火爆&#xff0c;AI搜索技术成为了公众和业界关注的焦点。这些技术不仅能够提供快速、准确的信息检索&#xff0c;还能够通过自然语言处理技术理解用户的复杂查询&am…

步进电机(STM32+28BYJ-48)

一、简介 步进电动机&#xff08;stepping motor&#xff09;把电脉冲信号变换成角位移以控制转子转动的执行机构。在自动控制装置中作为执行器。每输入一个脉冲信号&#xff0c;步进电动机前进一步&#xff0c;故又称脉冲电动机。步进电动机多用于数字式计算机的外部设备&…

vue的学习--day3

1、尝试使用json文件模拟增删改查 json server:准备一份自己的数据&#xff08;这里我用的是老师给的&#xff09;。 转到d盘&#xff0c;然后打开json文件&#xff1a; 下面模拟增删改查&#xff1a; 借助工具postman或apifox或apipost&#xff1a; 这里我下载了apifox&…

养老院生活管理系统

摘要 随着全球范围内人口老龄化趋势的日益加剧&#xff0c;养老院作为老年人生活的重要场所&#xff0c;其生活管理问题也显得愈发突出和重要。为了满足养老院在日常生活管理、老人健康监护、服务人员管理等多方面的需求&#xff0c;提高管理效率和服务质量。决定设计并实现了…

鸿蒙小案例-自定义键盘

一个自定义键盘 效果 完成简单的26键中英文输入 使用&#xff1a; Entry Component struct IndexInput {State text: string inputController: TextInputController new TextInputController()//自定义键盘关闭事件hideClick(){this.inputController.stopEditing()}//自定义…

Java SpringBoot MongoPlus 使用MyBatisPlus的方式,优雅的操作MongoDB

Java SpringBoot MongoPlus 使用MyBatisPlus的方式&#xff0c;优雅的操作MongoDB 介绍特性安装新建SpringBoot工程引入依赖配置文件 使用新建实体类创建Service测试类进行测试新增方法查询方法 官方网站获取本项目案例代码 介绍 Mongo-Plus&#xff08;简称 MP&#xff09;是一…

Windows 11 安装 Python 3.11 完整教程

Windows 11 安装 Python 3.11 完整教程 一、安装包安装 1. 下载 Python 3.11 安装包 打开浏览器,访问 Python 官方下载页面。点击“Download Python 3.11”,下载适用于 Windows 的安装包(Windows installer)。 2. 安装 Python 3.11 运行下载的安装包 python-3.11.x-amd6…

(论文版)深度学习 | 基于 VGG16-UNet 语义分割模型的猫狗图像提取研究

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本实验本项目基于 VGG16-UNet 架构&#xff0c;利用 Labelme 标注数据和迁移学习&#xff0c;构建高效准确的猫狗图像分割模型。通过编码器-解码器结构&#xff08;特征提取-上采样&#xff09;提升分割精度&#xff0c;适应不同…

Spring学习03-[Spring容器核心技术IOC学习进阶]

IOC学习进阶 Order使用Order改变注入顺序实现Ordered接口&#xff0c;重写getOrder方法来改变自动注入顺序 DependsOn使用 Lazy全局设置-设置所有bean启动时候懒加载 Scopebean是单例的&#xff0c;会不会有线程安全问题 Order 可以改变自动注入的顺序 比如有个animal的接口&a…

爬虫-豆瓣电影排行榜

获取数据 requests库 获取数据环节需要用到requests库。安装方式也简单 pip install requests 爬取页面豆瓣读书 Top 250 用requests库来访问 import requests res requests.get(https://book.douban.com/top250/) 解析&#xff1a; 导入requests库调用了requests库中的…

网络IO模型之多路复用器.md

多路复用是什么&#xff1f;怎么理解&#xff1f; 本文主要涉及为 程序中处理网络IO时的模型&#xff0c;对于系统内核而言网络IO模型。这里只做普及使用 前置知识&#xff0c;什么是IO&#xff1f;怎么理解IO IO其实就是In和Out。中文翻译是输入和输出&#xff0c;只要涉及到输…

SQL二次注入原理分析

二次注入在测试的时候比较少见&#xff0c;或者说很难被测出来&#xff0c;因为测的时候首先要去找注入的位置&#xff0c;其次是去判断第一次执行的SQL语句&#xff0c;然后还要去判断第二次进行调用的 SQL 语句。而关键问题就出在第二次的调用上面。 下面以一个常用过滤方法…

mmaction2版本适配(Linux)

从cuda到mmcv保姆式教程 &#xff08;数十年踩坑经验&#xff0c;跟着我做&#xff0c;版本不会错~&#xff09; 如果有补充&#xff0c;请评论区评论&#xff0c;后续填坑&#xff01; cuda11.3 下载安装包 wget https://developer.download.nvidia.com/compute/cuda/11.3…