线性表(从数据结构的三要素出发)

news2024/11/25 20:41:48

文章目录

  • 逻辑结构
  • 存储结构
    • 顺序存储
    • 链式存储
      • 单链表
      • 双链表
      • 循环单链表
      • 循环双链表
      • 静态链表
  • 数据的操作
    • 顺序结构
    • 链式结构
      • 单链表
      • 双链表

逻辑结构

线性表是具有相同数据类型的 n ( n ≥ 0 ) n(n≥0) n(n0)个数据元素的有限序列,其中 n n n为表长,当 n = 0 n=0 n=0时线性表是一个空表。若用 L L L命名线性表,则其一般表示为

L = ( a 1 , a 2 , ⋯   , a i , a i + 1 , ⋯   , a n ) L=\left(a_1, a_2, \cdots, a_i, a_{i+1}, \cdots, a_n\right) L=(a1,a2,,ai,ai+1,,an)

式中, a 1 a_1 a1是唯一的“第一个”数据元素,又称表头元素; a n a_n an是唯一的“最后一个”数据元素,又称表尾元素。除第一个元素外,每个元素有且仅有一个直接前驱。除最后一个元素外,每个元素有且仅有一个直接后继。

线性表有以下特性:

  • 表中元素的个数有限。
  • 表中元素具有逻辑上的顺序性,表中元素有其先后次序。
  • 表中元素都是数据元素,每个元素都是单个元素。
  • 表中元素的数据类型都相同,这意味着每个元素占有相同大小的存储空间。
  • 表中元素具有抽象性,即仅讨论元素间的逻辑关系,而不考虑元素究竟表示什么内容。

存储结构

顺序存储

它是用一组地址连续的存储单元依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。第1个元素存储在顺序表的起始位置,第i个元素的存储位置后面紧接着存储的是第 i + 1 i+1 i+1个元素,称 i i i为元素 a i a_i ai在顺序表中的位序。因此,顺序表的特点是表中元素的逻辑顺序与其存储的物理顺序相同

假设顺序表L存储的起始位置为LOC(A),sizeof(ElemType)是每个数据元素所占用存储空间的大小。

在这里插入图片描述

typedef struct {
	ElemType data[Maxsize];
	int length;
} SqList;

存在的问题:

  • 需要大量连续的存储空间
  • 插入删除时,时间复杂度高
  • 顺序表一旦确定大小,后续将不可扩充

链式存储

链式存储线性表时,不需要使用地址连续的存储单元,即不要求逻辑上相邻的元素在物理位置上也相邻,它通过“链”建立元素之间的逻辑关系,因此插入和删除操作不需要移动元素,而只需修改指针,但也会失去顺序表可随机存取的优点

单链表

在这里插入图片描述

typedef struct LNode {
	ElemType data;
	struct LNode *next;
} LNode, *LinkList;

存在的问题:

  • 失去了顺序存储中随机存取的特性
  • 求表长的时间复杂度高
  • 访问前驱结点的时间复杂度高

双链表

在单链表中要访问某个结点的前驱(插入、删除操作时),只能从头开始遍历,访问前驱的时间复杂度为 O ( n ) O(n) O(n)。为了克服单链表的这个缺点,引入了双链表,双链表结点中有两个指针priornext,分别指向其直接前驱和直接后继。表头结点的 prior域和尾结点的 next 域都是 NULL

在这里插入图片描述

typedef struct DNode {
	ElemType data;
	struct DNode *next, prior;
} DNode, *DLinkList;

循环单链表

循环单链表和单链表的区别在于,表中最后一个结点的指针不是NULL,而改为指向头结点,从而整个链表形成一个环。

在这里插入图片描述

循环双链表

由循环单链表的定义不难推出循环双链表。不同的是,在循环双链表中,头结点的prior指针还要指向表尾结点。

在这里插入图片描述

静态链表

静态链表是用数组来描述线性表的链式存储结构,结点也有数据域data 和指针域 next,与前面所讲的链表中的指针不同的是,这里的指针是结点在数组中的相对地址(数组下标),又称游标

在这里插入图片描述

typedef struct {
	ElemType data;
	int next;
} SLinkList[Maxsize];

数据的操作

顺序结构

初始化

void InitList(SqList &L)
{
	L.length = 0;
}

判满

bool isFull(SqList L)
{
	if (L.length == Maxsize) return true;
	return false;
}

判空

bool isEmpty(SqList L)
{
	if (L.length == 0) return true;
	return false;
}

插入操作

bool ListInsert(SqList &L, int i, ElemType e)
{
	if (i < 1 || i > L.length + 1)				// 无效的插入位置
		return false;

	if (isFull(L)) return false;				// 存储空间已满

	for (int j = L.length; j >= i; j -- )
		L.data[j] = L.data[j - 1];

	L.data[i - 1] = e;
	L.length ++ ;
	return true;
}

删除操作

bool ListDelete(SqList &L, int i, ElemType e)
{
	if (i < 1 || i > L.length + 1)				// 无效的删除位置
		return false;
	if (isEmpty(L)) return false;				// 数组是空的

	e = L.data[i - 1];
	for (int j = i; j < L.length; j ++ )
		L.data[j - 1] = L.data[j];

	L.length -- ;
	return true;
}

按值查找

int LocateElem(SqList L, ElemType e)
{
	for (int i = 0; i < L.length; i ++ )
		if (L.data[i] == e)
			return i + 1;
	return -1;
}

链式结构

单链表

初始化

void InitList(LinkList &L)
{
	L = (LNode *) malloc (sizeof(LNode));
	L->next = NULL;
}

求表长

int Length(LinkList L)
{
	LNode *p = L->next;
	int cnt = 0;			// 记录长度
	while (p)
	{
		cnt ++ ;
		p = p->next;
	}
	return cnt;
}

按序号查找结点

LNode * GetElem(LinkList L, int i)
{
	LNode *p = L->next;
	int cnt = 0;						// 记录当前遍历到第几个结点了
	while (p)
	{
		cnt ++ ;
		if (cnt == i)
			return p;
		p = p->next;
	}
	return NULL;
}

按值查找

LNode * LocateElem(LinkList L, ElemType e)
{
	LNode *p = L->next;
	while (p)
	{
		if (p->data == e)
			return p;
		p = p->next;
	}
	return NULL;
}

插入结点

在这里插入图片描述

bool ListInsert(LinkList &L, int i, ElemType e)
{
	LNode *p = L;
	int j = 0;
	while (p && j < i - 1)
	{
		p = p->next;
		j ++ ;
	}
	if (p == NULL) return false;		// 位置不合法

	LNode *s = (LNode *) malloc (sizeof(LNode));
	/*插入结点*/
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

删除结点
在这里插入图片描述

bool ListDelete(LinkList &L, int i, ElemType e)
{
	LNode *p = L;
	int j = 0;
	while (p && j < i - 1)
	{
		p = p->next;
		j ++ ;
	}
	if (p == NULL || p->next == NULL) return false;		// 位置不合法

	LNode *q = p->next;
	/*删除结点q*/
	e = q->data;
	p->next = q->next;
	free(q);
	return true;
}

采用头插法建立链表

在这里插入图片描述

LinkList List_HeadInsert(LinkList &L)
{
	LNode *s;
	int x;
	L = (LNode *) malloc (sizeof(LNode));
	L->next = NULL;
	scanf("%d", &x);
	while (x != 9999)		// 输入9999停止
	{
		s = (LNode *) malloc (sizeof(LNode));
		s -> data = x;
		s->next = L->next;
		L->next = s;
		scanf("%d", &x);
	}
	return L;
}

采用尾插法建立链表

在这里插入图片描述

LinkList List_TailInsert(LinkList &L)
{
	int x;
	L = (LNode *) malloc (sizeof(LNode));
	LNode *s, *r = L;		// r是表尾指针
	scanf("%d", &x);
	while (x != 9999)		// 输入9999停止
	{
		s = (LNode *) malloc (sizeof(LNode));
		s -> data = x;
		r->next = s;
		r = s;
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}

双链表

初始化

void InitList(DLinkList &L)
{
	L = (DNode *) malloc (sizeof(DNode));
	L->next = L->prior = NULL;
}

插入结点

在这里插入图片描述

bool ListInsert(DLinkList &L, int i, ElemType e)
{
	DNode *p = L;
	int j = 0;
	while (p && j < i - 1)
	{
		p = p->next;
		j ++ ;
	}
	if (p == NULL) return false;		// 位置不合法

	DNode *s = (DNode *) malloc (sizeof(DNode));
	/*插入结点*/
	s->data = e;
	s->next = p->next;
	p->next->prior = s;
	s->prior = p;
	p->next = s;
	return true;
}

删除结点

bool ListDelete(DinkList &L, int i, ElemType e)
{
	DNode *p = L;
	int j = 0;
	while (p && j < i - 1)
	{
		p = p->next;
		j ++ ;
	}
	if (p == NULL || p->next == NULL) return false;		// 位置不合法

	DNode *q = p->next;
	/*删除结点q*/
	e = q->data;
	p->next = q->next;
	q->next->prior = p;
	free(q);
	return true;
}

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

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

相关文章

Elasticsearch集群搭建学习

Elasticsearch集群聚合、集群搭建 RestClient查询所有高亮算分控制 数据聚合DSL实现Bucket聚合DSL实现Metrics聚合RestAPI实现聚合 拼音分词器如何使用拼音分词器&#xff1f;如何自定义分词器&#xff1f;拼音分词器注意事项&#xff1f; 自动补全数据同步集群搭建ES集群结构创…

C++—— set、map、multiset、multimap的介绍及使用

目录 关联式容器 关联式容器的特点和使用场景 树形结构与哈希结构 树形结构 哈希结构 键值对 set set的介绍 set的定义方式 set的使用 multiset map map的介绍 map的定义方式 map的使用 multimap 关联式容器 C标准模板库&#xff08;STL&#xff09;中的关联…

vue17:v-bind对css样式的控制增强

代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><styl…

软考之零碎片段记录(三十一)+复习巩固(错题整理,知识点总结,易错题)

1. 奇偶校验 只能检测一位数的错误。但无法纠正错误。若有奇数个数据位出错&#xff0c;可检测。有局限性。 2. 深度与广度优先遍历 参考题【【数据结构自用】1.图深度优先遍历2.找有向图中的强连通分量数目3.给出图的任意两个拓扑序列】https://www.bilibili.com/video/BV…

下雨!大水蚁引发的水文!看比赛咯,曼联VS曼城——早读(逆天打工人爬取热门微信文章解读)

唠唠嗑 水一水 引言Python 代码结尾 引言 今天星期六 大小周 一个等了很久的双休 昨天晚上真的是吓到我了 漫天的小飞虫 我一开始还以为是一两只 没想到那些小飞虫 从阳台不断飞进来 在山卡拉下面租房子 也是太恐怖了 来个特写 他们也就一个晚上的时间 成虫 天气合适 长翅…

Unity-Sprite Atlas+UGUI系统的运行原理

每日一句&#xff1a;别听世俗耳语&#xff0c;看自己的风景就好 目录 SA的原理&#xff1a; SA的优点&#xff1a; SA的缺点&#xff1a; DrawCall是什么&#xff1f; 批处理是什么&#xff1f; 我们先了解一下UGUI系统的运行原理吧&#xff01; 提到图集优化&#xff0…

【面试干货】数据库乐观锁,悲观锁的区别,怎么实现

【面试干货】数据库乐观锁&#xff0c;悲观锁的区别&#xff0c;怎么实现 1、乐观锁&#xff0c;悲观锁的区别2、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1、乐观锁&#xff0c;悲观锁的区别 悲观锁&#xff08;Pessimistic Lo…

会声会影调速怎么用 会声会影如何调整音频速度

会声会影是一款功能强大的视频编辑软件&#xff0c;可以帮助我们轻松的实现剪辑。 会声会影的操作简单易懂&#xff0c;界面简洁明快。适合家庭使用&#xff0c; 我们使用会声会影可以在家就能将视频剪辑成好莱坞大片。但是在使用的过程中&#xff0c;仍然会遇到一些操作上的问…

mac下安装airflow

背景&#xff1a;因为用的是Mac的M芯片的电脑&#xff0c;安装很多东西都经常报错&#xff0c;最近在研究怎么把大数据集群上的crontab下的任务都配置到一个可视化工具中&#xff0c;发现airflow好像是个不错的选择&#xff0c;然后就研究怎么先安装使用起来&#xff0c;后面再…

「React」useEffect 与 useLayoutEffect 使用与区别

前言 useEffect 与 useLayoutEffect 是两个 Hooks&#xff0c;前者比较常用&#xff0c;后者在一些场景下也会用到&#xff0c;下面说明两者区别和应用场景。 使用 useEffect 和 useLayoutEffect 是React Hooks里用于处理副作用的钩子&#xff08;Hooks&#xff09;&#x…

单机一天轻松300+ 最新微信小程序拼多多+京东全自动掘金项目、

现代互联网经济的发展带来了新型的盈利方式&#xff0c;这种方法通过微信小程序的拼多多和京东进行商品自动巡视&#xff0c;以此给商家带来增加的流量&#xff0c;同时为使用者带来利润。实践这一手段无需复杂操作&#xff0c;用户仅需启动相应程序&#xff0c;商品信息便会被…

自定义一个SpringBoot场景启动器

前言 一个刚刚看完SpringBoot自动装配原理的萌新依据自己的理解写下的文章&#xff0c;如有大神发现错误&#xff0c;敬请斧正&#xff0c;不胜感激。 分析SpringBoot自动配置原理 SpringBoot的启动从被SpringBootApplication修饰的启动类开始,SpringBootApplicaiotn注解中最…

单片机LCD1602显示电子时钟设计

基于52单片机电子时钟的设计 摘要 本次设计的多功能时钟系统采用STC89C52单片机为核心器件&#xff0c;利用其定时器/计数器定时和记数的原理&#xff0c;结合液晶显示电路、时钟芯片DS1302电路、电源电路以及按键电路来设计计时器。将软硬件有机地结合起来&#xff0c;使得系…

十一、Python循环语句「长期更新Python简单入门到适用」

在python中&#xff0c;它的循环语句有 for 与 while 1、while循环 在python 中 while 语句的一般形式&#xff1a; while 判断条件 : 声明 同样需要注意冒号和缩进。另外&#xff0c;在Python中没有 do..while 循环。 以下实例使用了 while 来计算 1 到 50 的总和&#…

Adobe Camera Raw 11 for Mac/win:摄影后期处理的革命性飞跃

在数字摄影的世界里&#xff0c;RAW格式以其未压缩的原始数据特性&#xff0c;为摄影师提供了更大的后期处理空间。而Adobe Camera Raw 11&#xff0c;作为这一领域的翘楚&#xff0c;以其卓越的性能和创新的功能&#xff0c;为摄影师们带来了前所未有的创作体验。 Adobe Came…

全网最全网络基础思维导图合集(38张)

计算机网络基础知识点多且杂&#xff0c;想要系统地学习&#xff0c;思维导图肯定是必不可少的。 今天整理了38张思维导图&#xff0c;帮助你轻松理清思路&#xff0c;快速掌握关键内容。建议你收藏起来慢慢看&#xff0c;在看过之后最好能重新动手画一画&#xff0c;让计算机…

如何使用DotNet-MetaData识别.NET恶意软件源码文件元数据

关于DotNet-MetaData DotNet-MetaData是一款针对.NET恶意软件的安全分析工具&#xff0c;该工具专为蓝队研究人员设计&#xff0c;可以帮助广大研究人员轻松识别.NET恶意软件二进制源代码文件中的元数据。 工具架构 当前版本的DotNet-MetaData主要由以下两个部分组成&#xf…

element-ui 前端ui框架用法开发指南(2024-05-22)

Element&#xff0c;一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库 1、npm安装 // npm安装&#xff1a;npm install element-ui --save 能更好地和 webpack 打包工具配合使用 2、cdn在线引入 访问最新版本的资源地址 - element-uiThe CDN for element-u…

C#解析JSON的常用库--Newtonsoft.Json

一、库介绍 在C#中&#xff0c;解析JSON的常用库有Newtonsoft.Json&#xff08;也称为Json.NET&#xff09;和 System.Text.Json&#xff08;从 .NET Core 3.0 开始引入&#xff09;。本文主要介绍 Newtonsoft.Json。 二、下载 官网&#xff1a; https://www.nuget.org/pack…

C语言之指针进阶(3),函数指针

目录 前言&#xff1a; 一、函数指针变量的概念 二、函数指针变量的创建 三、函数指针变量的使用 四、两段特殊代码的理解 五、typedef 六、函数指针数组 总结&#xff1a; 前言&#xff1a; 本文主要讲述C语言指针中的函数指针&#xff0c;包括函数指针变量的概念、创建…