【线性表】内容总结

news2024/11/28 12:49:22

1.单链表,循环链表,双向链表的循环效率

在这里插入图片描述

2.顺序表和链表的比较

1.什么是存储密度

1.定义:

存储密度是指结点数据本身所占的存储量整个结点结构中所占的存储量 之比,即:
在这里插入图片描述

2.实例

比如在32位系统上,一个12字节的结点中 存储8个字节的数据4个字节的指针
存储密度就不高 在这里插入图片描述
在这里插入图片描述

2.链式存储结构的优点

  • 结点空间可以动态申请和释放;
  • 数据元素的逻辑次序靠结点的指针来指示,插入和删除时不需要移动数据元素。

3.链式存储结构的缺点

  • 存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大。
  • 链式存储结构是非随机存取结构。对任一结点的操作都要从头指针依指针链査找到该结点,这增加了算法的复杂度。

4.顺序表和链表的差异性

在这里插入图片描述

3.线性表的应用(链式存储实现)

1.线性表的合并

1.问题描述:

假设利用两个线性表La和Lb分别表示两个集合A和B,现要求一个新的集合A=AUB

2.核心:
  • 去掉重复元素,取两个集合的并集

比如:
在这里插入图片描述

3.算法核心思路:

依次取出Lb 中的每个元素,执行以下操作:在La中查找该元素;如果找不到,则将其插入La的最后

4.链式存储需要用到的基本操作:
求表长
int LinkLength(LinkList L);

尾插建立新表
bool CreateLinkList(LinkList* L, int n);

按位查找元素e并获得对应值
bool GetElem(LinkList L, int i, Elem* e);

按值查找并返回位序(用到非0为真,0为假)
int LocateElem(LinkList L, Elem e);

按位插入(插入到i-1和i之间)
bool InsertElem(LinkList L, int i, Elem e);
5.链式存储的算法步骤:

(0)判断要合并的两个线性表头结点是否存在
(1)分别求La,Lb的表长
(2)定义变量e,用于存储要插入的元素值
(3)合并线性表La,Lb;将Lb中与La不重复的元素插入到La中
<1>依次取出Lb 中的每个元素
<2>在La中查找该元素,如果找不到,则将其插入La的表尾

bool unionLinkList(LinkList La, LinkList Lb)
int LinkLength(LinkList L);
bool CreateLinkList(LinkList* L, int n);
bool GetElem(LinkList L, int i, Elem* e);
int LocateElem(LinkList L, Elem e);
bool InsertElem(LinkList L, int i, Elem e);
//两个线性表的合并(带头结点的单链表的实现)
bool unionLinkList(LinkList La, LinkList Lb)
{
	//[0]判断要合并的两个线性表头结点是否存在
	if (!La && !Lb) 
	{
		return false;
	}

	//[1]分别求La,Lb的表长
	int La_Len = LinkLength(La);
	int Lb_Len = LinkLength(Lb);

	//[2]定义变量e,用于存储要插入的元素值
	Elem e;

	//[3]合并线性表La,Lb;将Lb中与La不重复的元素插入到La中
	for (int i = 1; i <=Lb_Len; i++)//注意:循环条件i<=Lb_Len,而不是i<Lb_Len;若为i<Lb_Len,合并时Lb会忽略判断最后一个元素。
	{

		//<1>依次取出Lb 中的每个元素:
		GetElem(Lb, i, &e);


		//<2>在La中查找该元素,如果找不到,则将其插入La的表尾
		if (!LocateElem((La), e))
		{
			InsertElem(La,++La_Len,e);//注意:插入位置为La_Len+1,使用 ++La_Len 而不是 La_Len++ 
			                          //是为了确保在插入元素时,La_Len 的值已经自增,插入位置已更新。
		}
	}
	return true;
}
6.小结:
  • 传入线性表若为不带头结点的两个链表,需要传入待合并线性表的头指针二级指针
bool unionLinkList(LinkList* La, LinkList Lb)
  • 注意循环条件i<=Lb_Len,而不是i<Lb_Len;若为i<Lb_Len,合并时Lb会忽略判断最后一个元素。
  • 注意插入位置为La_Len+1,使用 ++La_Len 而不是 La_Len++;先更新插入位置,再插入
7.带头结点单链表合并的实际操作:
//用单链表来实现:
#include<stdio.h>
#include<stdlib.h>

typedef int Elem;

#define bool int 
#define true 1
#define false 0

typedef struct Node
{
	Elem data;
	struct Node* next;
}Node,*LinkList;



//求表长
int LinkLength(LinkList L)
{
	if (!L)
	{
		return 0;
	}

	Node* p = L->next;

	int count = 0;
	
	while (p)
	{
		count++;
		p = p->next;
	}

	return count;
}


//尾插建立整表
bool CreateLinkList(LinkList *L,int n)
{
	//头结点
	*L = (LinkList)malloc(sizeof(Node));
	
	if (!(*L))
	{
		return false;
	}

	(*L)->next = NULL;

	//初始化尾指针
	LinkList Tail = *L;

	Node* p;

	//尾插建立
	for (int i = 0; i < n; i++)
	{
		p = (Node*)malloc(sizeof(Node));
		
		if (!p)
		{
			return false;
		}

		scanf_s("%d", &p->data);


		Tail->next = p;
		p->next = NULL;
		Tail = p;
	}
	return true;
}

//按位查找
bool GetElem(LinkList L, int i, Elem* e)
{
	//头结点,首元结点不存在
	if (!L||!(L->next))
	{
		return false;
	}

	Node* p = L->next;
	int j = 1;
	
	while (p && j < i)
	{
		p = p->next;
		j++;
	}

	if (!p)
	{
		return false;
	}

	//返回对应元素值
	*e = p->data;
	return true;
}


//按值查找(返回位序,非0为真,0为假)
int LocateElem(LinkList L,Elem e)
{
	//头结点,首元结点不存在
	if (!L || !(L->next))
	{
		return 0;
	}

	Node* p = L->next;
	int count = 1;
	
	while (p&&p->data!=e)
	{
		p = p->next;
		count++;
	}
	
	if (!p)
	{
		return 0;
	}

	return count;
}


//按位插入
bool InsertElem(LinkList L, int i, Elem e)
{
	//保证头结点存在
	if (!L)
	{
		return false;
	}

	Node* p = L;
	int j = 0;
	
	//找第i-1个元素
	while (p&&j<i-1)
	{
		p = p->next;
		j++;
	}

	if (!p)
	{
		return false;
	}

	//建立并初始化新结点
	Node* s = (Node*)malloc(sizeof(Node));
	
	if(!s)
	{
		return false;
	}

	s->data = e;

	//插入到对应位置

	s->next = p->next;
	p->next = s;
	return true;
}


//整表输出
bool printLinkList(LinkList L)
{
	if (!L || !L->next)
	{
		return false;
	}

	Node* p = L->next;
	
	while (p)
	{
		printf("%d-->", p->data);
		p = p->next;
	}

	
	printf("end\n");
	return true;
}



int LinkLength(LinkList L);
bool CreateLinkList(LinkList* L, int n);
bool GetElem(LinkList L, int i, Elem* e);
int LocateElem(LinkList L, Elem e);
bool InsertElem(LinkList L, int i, Elem e);

//两个线性表的合并(带头结点)
bool unionLinkList(LinkList La, LinkList Lb)
{
	//[0]判断要合并的两个线性表头结点是否存在
	if (!La && !Lb) 
	{
		return false;
	}

	//[1]分别求La,Lb的表长
	int La_Len = LinkLength(La);
	int Lb_Len = LinkLength(Lb);

	//[2]定义变量e,用于存储要插入的元素值
	Elem e;

	//[3]合并线性表La,Lb;将Lb中与La不重复的元素插入到La中
	for (int i = 1; i <=Lb_Len; i++)//注意1:循环条件i<=Lb_Len,而不是i<Lb_Len;若为i<Lb_Len,合并时Lb会忽略判断最后一个元素。
	{

		//<1>依次取出Lb 中的每个元素:
		GetElem(Lb, i, &e);


		//<2>在La中查找该元素,如果找不到,则将其插入La的表尾
		if (!LocateElem((La), e))
		{
			InsertElem(La,++La_Len,e);//注意4:插入位置为La_Len+1,使用 ++La_Len 而不是 La_Len++ 
			                          //是为了确保在插入元素时,La_Len 的值已经自增,插入位置已更新。
		}
	}
	return true;
}
int main()
{
	LinkList La;
	LinkList Lb;
	CreateLinkList(&La, 4);
	printf("La:\n");
	printLinkList(La);

	printf("\n");
	CreateLinkList(&Lb, 3);
	printf("Lb:\n");
	printLinkList(Lb);

	unionLinkList(La, Lb);

	printf("\n");
	printf("合并后:\n");
	printLinkList(La);

	return 0;
}

在这里插入图片描述

2.有序表的合并

1.问题描述:

已知线性表La 和Lb中的数据元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列

2.核心:
  • 两个集合中的所有元素
  • 非递减有序排列:即每个元素都大于或等于它前面的元素;
    比如:
    在这里插入图片描述
3.算法核心思路:创建一个空表Lc;依次从 La 或 Lb 中“摘取”元素值较小的结点插入到 Lc 表的最后,直至其中一个表变空为止;继续将 La 或 Lb 其中一个表的剩余结点插入在 Lc 表的最后
4. 链式存储的算法步骤:

(1) 定义三个临时指针:
//pa用来遍历La
//pb用来遍历Lb
//pc用来遍历新链表Lc的每个结点
(2)初始化pa,pb分别指向La,Lb的首元结点,pc指向新链表的头结点
//新链表的头结点可以是La的头结点,也可以是Lb的头结点
(3)依次从 La 或 Lb 中摘取元素值较小的结点插入到 Lc 表的最后,直至其中一个表变空为止
(4)插入剩余段(注意释放没用的头结点)

pc->next = pa ? pa : pb;
等价于
if(pa!=NULL)
{
pc->next=pa;
}
else
{
pc->next=pb;
}

bool MergeList(LinkList* La, LinkList* Lb, LinkList* Lc)
bool MergeList(LinkList* La, LinkList* Lb, LinkList* Lc)
{
	//[1]定义三个临时指针:
	//pa用来遍历La
	//pb用来遍历Lb
	//pc用来遍历新链表Lc的每个结点	
	Node* pa, * pb, * pc;


	//[2]初始化pa,pb分别指向La,Lb的首元结点,pc指向新链表的头结点
	pa = (*La)->next;
	pb = (*Lb)->next;
	(*Lc) = (*La);//用La的头结点作为新链表Lc的头结点(当然也可以使用Lb的头结点)
	pc = (*Lc);//实际上pc指向的是La的头结点


	//[3]依次从 La 或 Lb 中摘取元素值较小的结点插入到 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;
		}
	}

	//[4]插入剩余段
	pc->next = pa ? pa : pb;//若pa不为空,链接pa;否则链接pb

	//释放Lb的头结点
	free(*Lb);
	return true;
}
5.思路图解
    • 1
      在这里插入图片描述
    • 2
      在这里插入图片描述
    • 3
      在这里插入图片描述
    • 4
      在这里插入图片描述
    • 5
      在这里插入图片描述
    • 6
      在这里插入图片描述
6.小结:
  • 新表的头结点可以选择任意一个表的头结点,示实际情况灵活运用
  • 当传入不带头结点的两个表时,可以自己建立一个虚拟头结点,方便进行操作
7.带头结点有序单链表合并的实际操作:
#include<stdio.h>
#include<stdlib.h>

typedef int Elem;

#define bool int 
#define true 1
#define false 0

typedef struct Node
{
	Elem data;
	struct Node* next;
}Node, * LinkList;


//尾插建立整表
bool CreateLinkList(LinkList* L, int n)
{
	//头结点
	*L = (LinkList)malloc(sizeof(Node));

	if (!(*L))
	{
		return false;
	}

	(*L)->next = NULL;

	//初始化尾指针
	LinkList Tail = *L;

	Node* p;

	//尾插建立
	for (int i = 0; i < n; i++)
	{
		p = (Node*)malloc(sizeof(Node));

		if (!p)
		{
			return false;
		}

		scanf_s("%d", &p->data);


		Tail->next = p;
		p->next = NULL;
		Tail = p;
	}
	return true;
}

//整表输出
bool printLinkList(LinkList L)
{
	if (!L || !L->next)
	{
		return false;
	}

	Node* p = L->next;

	while (p)
	{
		printf("%d-->", p->data);
		p = p->next;
	}


	printf("end\n");
	return true;
}


bool MergeList(LinkList* La, LinkList* Lb, LinkList* Lc)
{
	//[1]定义三个临时指针:
	//pa用来遍历La
	//pb用来遍历Lb
	//pc用来遍历新链表Lc的每个结点	
	Node* pa, * pb, * pc;


	//[2]初始化pa,pb分别指向La,Lb的首元结点,pc指向新链表的头结点
	pa = (*La)->next;
	pb = (*Lb)->next;
	(*Lc) = (*La);//用La的头结点作为新链表Lc的头结点(当然也可以使用Lb的头结点)
	pc = (*Lc);//实际上pc指向的是La的头结点


	//[3]依次从 La 或 Lb 中摘取元素值较小的结点插入到 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;
		}
	}

	//[4]插入剩余段
	pc->next = pa ? pa : pb;

	//释放Lb的头结点
	free(*Lb);
	return true;
}


int main()
{
	LinkList La, Lb, Lc;//这里的Lc并不需要未初始化,用来新链表的头指针,它可以指向La和Lb中任意一个表中的头结点
	CreateLinkList(&La, 3);
	printf("La:\n");
	printLinkList(La);

	printf("\n");
	CreateLinkList(&Lb, 6);
	printf("Lb:\n");
	printLinkList(Lb);
	
	MergeList(&La, &Lb, &Lc);
	printf("Lc:\n");
	printLinkList(Lc);

	return 0;
}

在这里插入图片描述

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

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

相关文章

保姆级Python与PyCharm安装教程

本文演示所用的所用的所有工具包都已经打包好了&#xff0c;【点击这里】即可获得 一、简介 Python是一种广泛使用的高级编程语言&#xff0c;因其简洁的语法和丰富的库支持&#xff0c;在数据科学、Web开发、人工智能等领域广受欢迎。PyCharm是由JetBrains开发的一款针对Pyt…

一篇文章带你了解归并排序-分治法

文章目录 两个有序数组排序一个局部有序数组排序分治法归并排序 两个有序数组排序 先来一个场景假设&#xff0c;先有两个有序数组{1,3,5,9}、{2,4,6,8}&#xff0c;要求合并成一个有序数组。 我们先上一段简单的处理代码 public static int[] merge(int[] leftArr, int[] righ…

Redis后台线程之非阻塞删除

当Redis执行删除命令的时候&#xff0c;如果被删除的对象是列表、集合、散列类型&#xff0c;因为这些数据类型包含的元素存放在不同的内存块中&#xff0c;redis需要遍历所有元素来释放其对应的内存块空间&#xff0c;这个耗时操作可能导致redis阻塞&#xff0c;redis4提供的U…

[数据集][目标检测]agvs仓储机器人检测数据集VOC+YOLO格式967张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;967 标注数量(xml文件个数)&#xff1a;967 标注数量(txt文件个数)&#xff1a;967 标注类别…

API接口安全101:基础概念与最佳实践

文章目录 API定义协议架构风格描述语言 Webservicewsdl介绍复现 SOAPswagger介绍指纹查找利用存在目录复现 HTTPWebpack介绍复现 在当今数字化时代,API接口已成为现代软件架构中不可或缺的组成部分。它们连接着各种应用程序和服务,促进了数据交换和功能集成。然而,随着API的普及…

【PyTorch】神经网络的基本骨架-nn.Module的使用以及convolution-layers卷积层介绍

前提文章目录 【PyTorch】深度学习PyTorch环境配置及安装【详细清晰】 【PyTorch】深度学习PyTorch加载数据 【PyTorch】关于Tensorboard的简单使用 【PyTorch】关于Transforms的简单使用 【PyTorch】关于torchvision中的数据集以及dataloader的使用 文章目录 前提文章目录nn.…

从易车“超级818冠军之夜” 看如何借势体育营销点燃汽车消费热潮

编辑 | 魏力 发布 | 大力财经 导语&#xff1a;这个8月&#xff0c;是属于奥运的8月。 巴黎奥运会虽圆满落幕&#xff0c;但属于奥运健儿们的热度还在持续。在这股奥运热潮的带动下&#xff0c;全民运动热情持续释放&#xff0c;同时也激发出巨大的消费潜力。 赛场外&#…

Go 1.23中值得关注的几个变化

距离上一次Go 1.22版本发布[1]又过去六个月了&#xff0c;我们如期迎来了Go 1.23版本的发布](https://mp.weixin.qq.com/s/IpDUOe0AUDKW2PYCWmvLYw)。 对于Go项目乃至整个Go社区而言&#xff0c;这个版本还有一点额外的意义&#xff0c;那就是这是Russ Cox[2]作为Tech lead&…

nginx 日志格式化,每日分割文件(已亲测)

首先nginx版本是1.23.4&#xff0c;在安装目录的conf文件夹下&#xff0c;配置nginx.conf。配置如下&#xff1a; logformat 代表日志格式设置 frmain 代表日志配置别名 map 行代表设置每日切割文件格式 需要在配置文件location指定访问的路径下&#xff0c;配置日志输出路径…

AI自动生成PPT怎么用?5大AI生成PPT技巧教会你

处暑悄然而至&#xff0c;标志着炎热夏季的逐渐远去&#xff0c;自然界的万物开始步入收获与沉淀的季节。值此节气更迭之际&#xff0c;何不借助现代科技的力量&#xff0c;用一份精美的PPT来宣传处暑的独特魅力&#xff1f; 无需繁琐制作&#xff0c;AI生成PPT免费工具就能助…

C学习(数据结构)-->实现链式结构二叉树

目录 一、链式二叉树结构 二、实现 1、申请新结点 2、前、中、后序遍历 1&#xff09;前序遍历 例&#xff1a; 2&#xff09;中序遍历 3&#xff09;后序遍历 3、结点个数 1&#xff09;二叉树结点个数 例&#xff1a;​编辑 2&#xff09;二叉树叶子结点个数 3&…

C++入门基础知识27

成长路上不孤单&#x1f60a;【14后小学生一枚&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff08;&#xff01;&#xff01;&#xff01…

工厂老板、设计师怎么选通风采光天窗?重点关注哪些方面?

选通风采光天窗首先看预算与通风采光需求&#xff0c;然后看品牌和售后&#xff0c;选购过程中重点关注天窗的型号、规格尺寸、材料配置、外观造型及颜色。一、预算与通风采光需求 通风采光天窗已成为厂房建筑上必备的屋顶设备&#xff0c;现目前天窗的型号多样&#xff0c;价位…

原神4.8版本重点培养和抽到角色数据表:修改了添加倒计时.隐藏了抽到角色数据表删除按钮、备注列和选择列

<!DOCTYPE html> <html lang"zh-cn"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>原神4.8版本抽到角色和重点培养数据表</title…

七牛云 CDN 视频瘦身,为视频分发「减负增效」

随着智能设备的普及&#xff0c;以及各种以分享视频为主的平台的兴起&#xff0c;人们记录生活、分享故事的方式不再局限于文字和图片&#xff0c;而是越来越多地通过视频来表达。视频也不再需要复杂的制作过程&#xff0c;变得随手可得。 然而&#xff0c;视频在互联网上的爆炸…

mac os 外接设备使用win习惯快捷键

目录 1. 简单映射版本&#xff08;常用快捷键&#xff09;2. 如果想追求完全的win匹配3. 关于外接鼠标滚动设置 1. 简单映射版本&#xff08;常用快捷键&#xff09; 就把ctrl和Command键互换一下就行 点击设置-键盘-键盘快捷键 然后在修饰键中&#xff0c;将control和comm…

怎么恢复电脑删除的文件?全面指南助你找回宝贵数据

在数字化时代&#xff0c;电脑中的文件承载着我们的工作成果、学习资料、珍贵照片以及无数回忆。然而&#xff0c;不小心删除重要文件的情况时有发生&#xff0c;让人心急如焚。别担心&#xff0c;本文将为你提供一份全面的指南&#xff0c;教你如何恢复电脑中删除的文件&#…

虚幻5|AI视力系统,听力系统,预测系统(2)听力系统

虚幻5|AI视力系统&#xff0c;听力系统&#xff0c;预测系统&#xff08;1&#xff09;视力系统-CSDN博客 一&#xff0c;把之前的听力系统&#xff0c;折叠成函数&#xff0c;复制粘贴一份改名为听力系统 1.小个体修改如下&#xff0c;把之前的视力系统改成听力系统 2.整体修…

Java—Lambda表达式

注意&#xff1a;如果无法判断一个方法是否为函数式接口&#xff0c;可以查看该方法的源码中是否携带FunctionalInterface注解。 lambda表达式再简化写法规则如下。 1. 参数类型可以省略不写 2. 如果只有一个参数&#xff0c;参数的 "( )" 也可以省略。 3. 如果Lambd…

使用Java和XPath在XML文档中精准定位数据

在当今数据驱动的世界中&#xff0c;能够从复杂的文档结构中准确地提取信息是一项极具价值的技能。XML文档因其结构化和可扩展性广泛用于各种应用中&#xff0c;而XPath则是一种强大而灵活的语言&#xff0c;专门用于在这些文档中进行导航和数据提取。本篇文章将带您深入了解如…