【数据结构】--顺序表

news2024/10/10 6:13:17

👻个人主页: 起名字真南
👾个人专栏: [数据结构初阶] [C语言]

请添加图片描述

目录

  • 1 线性表
  • 2 顺序表
    • 2.1 概念和结构
    • 2.2 顺序表的实现
      • 2.2.1 头文件的定义
      • 2.2.2 初始化
      • 2.2.3 检查空间大小
      • 2.2.4 尾插
      • 2.2.5 打印
      • 2.2.6 头插
      • 2.2.7 查找指定数据
      • 2.2.8 头删
      • 2.2.9 尾删
  • 2倍

1 线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列,线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表,链表,栈,队列,字符串…
线性表在逻辑上是连续的,是一种线性结构但是在物理上(内存中存储)不一定是连续的。线性表在物理上存储时通常是以数组或者链表的形式技能型存储。

在这里插入图片描述

2 顺序表

2.1 概念和结构

顺序表使用一段物理地址连续的存储单元来进行储存数据的线性结构。一般情况下底层是数组。

1 静态顺序表:使用定长数组储存元素

在图片中N的实际大小为7使用define进行定义是为了方便后期数据的修改,其中arr指向的是数组首元素的地址,size指向的是最后一个元素的尾端实际大小为4但是在数组中以0为第一个下标是所以是尾端

2 动态顺序表:使用动态开辟的数组进行存储
在这里插入图片描述
动态顺序表比静态顺序表多了一个capacity用来记录目前所开辟空间的大小并且使用指针来指向动态开辟的数组而不是使用数组名。

2.2 顺序表的实现

静态顺序表只适用于确定的数据元素的个数,如果不确定空间开多了则会造成浪费,开少了不够用,所以我们一般使用动态顺序表,根据需求来开辟空间。

2.2.1 头文件的定义

typedef int SeqListDataType;
typedef struct SeqList
{
	SeqListDataType* arr;  // 指向动态开辟的数组
	size_t size;              //有效数据个数
	size_t capacity;          //开辟空间的大小

}SeqList;

2.2.2 初始化

关于顺序表的初始化有两种方法,第一种是直接给capacity初始化为一个任意的值,第二种则是初始化为0。
第一种初始化方法,在这里我们需要注意因为在初始的条件下我们是给定了空间的,所以这里的arr则不能为空必须开辟空间,在这里我们使用malloc来开辟空间。

void SeqListInit(SeqList* SL)
{
	assert(SL);
	SL->capacity = 4;
	SL->size = 0;
	SL->arr = (SeqListDataType*)malloc(SL->capacity * sizeof(SeqListDataType));
}

第二种方法则是初始化为0

void SeqListInit(SeqList* SL)
{
	assert(SL);
	SL->capacity = 0;
	SL->size = 0;
	SL->arr = NULL;
}

2.2.3 检查空间大小

我们不管是进行头插还是尾插都需要检查开辟的空间是否能够满足当前的需求,所以在进行对数据的修改的时候需要判断空间是否足够?

void SeqListCheck(SeqList* SL)
{
	assert(SL);
	//检查数据和空间的大小
	if (SL->capacity == SL->size)
	{
		//三目表达式
		size_t newcapacity = SL->capacity == 0 ? 4 : 2 * SL->capacity;
		SeqListDataType* tmp = (SeqListDataType*)realloc(SL->arr, newcapacity * sizeof(SeqListDataType));
		if (tmp == NULL)
		{
			perror("realloc:");
			exit(1);     //直接退出程序不再执行
		}
		SL->capacity = newcapacity;
		SL->arr = tmp;
	}
}

这个检查空间大小是在空间初始化为0的时候的代码,我们运用到了一个三目操作符来判断空间是否为空,判断的目的是因为if的循环条件是当空间大小等于数据个数来进行循环,但是满足这种条件有两种情况,第一种就是顺序表为空的情况空间大小和数据个数都是0,第二种就是这里面的数据已经满了需要开辟空间,如果我们开辟了空间的话需要修改的数据是两个,一个是空间大小,另一个是将动态开辟的空间给arr。
注意我们在开辟空间的时候最好创建一个临时的变量用来接收,因为一旦如果开辟失败realloc则会返回NULL赋给我们的arr这样就会造成数据的丢失,为了避免这种情况我们先创建一个临时变量并判断是否开辟成功,如果不为空则将tmp赋值给arr。如果初始化的时候是直接赋值那么这里的三目操作符可以省略,直接SL->capacity = 2 * SL->capacity就可以了。

2.2.4 尾插

在定义中定义的数组中元素的个数size不仅可以作为记录顺序表中数据的多少同时也可以作为指向顺序表最后一个元素的下一个地址的指针,
在这里插入图片描述
所以我们在进行尾插数据的时候直接在size位置插入即可。注意我们每次进行插入数据的时候都要判断是否为空并且检查空间的小。因为我们需要对顺序表进行修改所以需要传指针(*),结尾记得size++

void SLPushBack(SeqList* SL, SeqListDataType data)
{
	assert(SL);
	SeqListCheck(SL);
	SL->arr[SL->size] = data;
	SL->size++;
}

2.2.5 打印

因为我们有size用来记录数组中元素的大小所以只需要一个for循环遍历即可

void SLPrint(SeqList SL)
{
	int i = 0;
	for ( i ; i < SL.size; i++)
	{
		printf("%d ", SL.arr[i]);
	}
	printf("\n");
}

2.2.6 头插

顺序表的头插想要执行这个操作就需要将顺序表中的所有数据向后移动一个位置然后将数据头插在下标为0的地点。
在这里插入图片描述

为了保护数据在移动的时候不会出错所以我们直接从size-1的位置(最后一个元素的地址)开始向size(最后一个元素的下一个地址)移动就不会丢失数据。如果从第一个开始向后移动则会覆盖原有的数据在造成数据的丢失。

void SLPushFront(SeqList* SL, SeqListDataType data)
{
	assert(SL);
	SeqListCheck(SL);
	for (int i = SL->size; i > 0; i--)
	{
		SL->arr[i] = SL->arr[i - 1];
	}
	SL->arr[0] = data;
	SL->size++;
}

2.2.7 查找指定数据

在查找数据的时候可以不传指针但是为了代码的一致性和美观所以这里传的是指针,

size_t SLFind(SeqList* SL, SeqListDataType data)
{
	assert(SL);
	for (int i = 0; i < SL->size; i++)
	{
		if (SL->arr[i] == data)
		{
			return i;
		}
	}
	printf("没有找到%d", data);
}

2.2.8 头删

进行头删的时候我们只需从第二个数据开始向前移动一位覆盖掉第一位的数据即可,需要注意的是循环条件是 i < SL->size - 1,而不是size,举一个简单的例子,如图所示包含四个数据的顺序表只需要执行三次即可。
在这里插入图片描述

void SLPopFront(SeqList* SL)
{
	assert(SL);
	for (int i = 0; i < SL->size - 1; i++)
	{
		SL->arr[i] = SL->arr[i + 1];
	}
	SL->size--;
}

2.2.9 尾删

void SLPopBack(SeqList* SL, SeqListDataType data)
{
	assert(SL);
	assert(SL->size > 0);
	SL->size--;
}

2倍

关于为什么每次开辟的空间是原空间的2倍的问题,这是个数学问题如果感兴趣的可以去网上搜索一下相关证明(我不说的因为是我不会)。

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

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

相关文章

浏览器扩展V3开发系列之 chrome.contextMenus 右键菜单的用法和案例

【作者主页】&#xff1a;小鱼神1024 【擅长领域】&#xff1a;JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 chrome.contextMenus 允许开发者向浏览器的右键菜单添加自定义项。 在使用 chrome.contextMenus 之前…

基于 Redis 实现秒杀资格判断,提升并发性能

在互联网电商平台上&#xff0c;秒杀活动往往会吸引大量用户同时抢购&#xff0c;如何高效地处理高并发请求&#xff0c;保证用户体验&#xff0c;是一个重要的技术挑战。本文将介绍如何基于 Redis 实现秒杀资格的判断&#xff0c;提高并发性能。 基本思路 秒杀活动的核心流程…

SpringBoot整合MongoDB JPA使用

一、整合MongoDB SpringDataMongoDB是 SpringData家族成员之一&#xff0c;MongoDB的持久层框架&#xff0c;底层封装了 mongodb-driver。mongodb-driver 是 MongoDB官方推出的 Java连接 MongoDB的驱动包&#xff0c;相当于JDBC驱动。 SpringBoot整合 MongoDB&#xff0c;引入…

MySQL数据库—MHA高可用配置及故障切换

目录 一、MHA概述 1.什么是 MHA 2.MHA 的组成 &#xff08;1&#xff09;MHA Node&#xff08;数据节点&#xff09; &#xff08;2&#xff09;MHA Manager&#xff08;管理节点&#xff09; (3)MHA 的特点 二、MHA的一主两从部署 实验设计 实验具体操作 1.配置主…

一次breach1靶机的渗透测试

1.端口扫描和信息收集 2.CMS后台信息收集 3.解密HTTPS流量 4.tomcat的后台利用 5.提权 1.端口扫描和信息收集&#xff1a; 首先进行主机发现&#xff0c;找到目标机器&#xff1a; nmap -sP 192.168.110.1/24 找到目标机器&#xff0c;进行端口扫描&#xff1a; nmap -T4 …

CS144 Lab3 TCPSender复盘

一.基础概念 1.TCPSender在TCPSocket中的地位与作用 Lab0中实现了基于内存模拟的流控制-字节流&#xff08;ByteStream&#xff09;&#xff0c;底层使用std::deque实现&#xff0c;根据最大容量Capacity进行容量控制。个人理解它相当于应用层的输入输出缓存区&#xff0c;用户…

【opencv - C++ - Ubuntu】putText 显示中文最快方法

话不多说&#xff0c;直接上代码 #include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/freetype.hpp>using namespace std; using namespace cv;int main(void) {Mat image(1000, 1800, CV_8UC3, Scalar(200,162,33));Ptr<freetype::F…

如何找到合适的Python第三方库?

找合适的Python库其实很简单&#xff0c;按照以下三步法&#xff0c;你能找到90%的Python库。 1、百度谷歌搜索 明确自己的需求&#xff0c;用Python来干什么&#xff0c;力求简短明了。比如定位“数据分析”&#xff0c;然后去搜索关键词【Python数据分析第三方库】&#xf…

【嵌入式Linux】i.MX6ULL 外部中断服务函数的初始化

文章目录 1. Cortex-A7 中断系统1.1 分析1.2 具体处理流程 2. 外部中断服务函数的初始化2.1 基本流程分析2.2 具体代码分析2.2.1. 定义中断处理类型和结构体2.2.2. 初始化中断系统2.2.3. 注册中断处理函数2.2.4. 具体的中断处理逻辑2.2.5. 默认的中断处理函数 3. 完整代码 本文…

django学习入门系列之第三点《案例 小米商城二级菜单》

文章目录 样例划分区域搭建骨架logo区域完整代码 小结往期回顾 样例 划分区域 搭建骨架 <!-- 二级菜单部分 --> <div class"sub-header"><div class"container"><div class"logo">1</div><div class"sea…

[word] Word表格怎么填充序列号? #微信#微信#笔记

Word表格怎么填充序列号&#xff1f; Word表格怎么填充序列号&#xff1f;在Excel中填充序列号是很轻松的事情&#xff0c;在Word表格中填充序列号就没那么简单&#xff0c;但是还是有小技巧&#xff0c;可以实现Word表格序号填充&#xff0c;还能自动更新。 1、插入序号 先…

JAVAEE之网络原理_传输控制协议(TCP)的滑动窗口、流量控制、拥塞控制、延迟应答、捎带应答机制

前言 在前面几节&#xff0c;我们讲解了TCP协议的基本概念、报文格式。还介绍了确认应答机制、超时重传、连接管理机制&#xff0c;在本节中 我们将会继续介绍TCP协议的其他机制。 一、滑动窗口机制&#xff08;效率机制&#xff09; 在前面的章节中我们讨论了确认应答策略&…

C++ ─── vector的实现

知识点&#xff1a; ① 因为vector是模版&#xff0c;所以声明和定义都放在.h中&#xff0c;防止出现编译错误 .h不会被编译&#xff0c;在预处理中.h在.cpp中展开所以在编译时只有.cpp 而 .cpp顺序编译&#xff0c;只会进行向上查找&#xff0c;因此至少有函数的声明。 ②memc…

【Linux】进程 | 控制块pcb | task_struct | 创建子进程fork

目录 Ⅰ. 进程的概念&#xff08;Process&#xff09; 1. 什么是进程&#xff1f; 2. 多进程管理 3. 进程控制块&#xff08;PCB&#xff09; task_struct 的结构 Ⅱ. 进程查看与管理 1. 使用指令查看进程 2. /proc 查看进程信息 3. 获取进程 ID 4. 创建子进程 原因…

在Ubuntu22.04 使用stable-diffusion-webui 秋叶整合包

背景 众所周知&#xff0c;赛博菩萨已经发布了windows下的整合包&#xff0c;开箱即用&#xff0c;且集成度较高。 那我为啥非要在Ubuntu下使用呢&#xff1f; 当然是因为主力机就是Ubuntu系统啦。而且涉及到sd webui API 的调用&#xff0c;在Ubuntu 下调试更加方便一点。 那…

PG实践|内置函数之GENERATE_SERIES之深入理解

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…

2024年第十五届蓝桥杯青少组大赛8月24日开启

据蓝桥杯青少组官网显示&#xff0c;2024年第十五届蓝桥杯青少组大赛8月24日开启。 蓝桥杯青少组历届题库地址&#xff1a;http://www.6547.cn/question/cat/2 蓝桥杯青少组历届真题下载&#xff1a;http://www.6547.cn/wenku/list/10

【神经网络】CNN网络:深入理解卷积神经网络

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&#xff01; CNN网络&#xff1a;深入理解…

VideoLLaMA 2:多模态视频理解新突破,音频理解能力再升级,挑战 GPT-4V

前言 近年来&#xff0c;人工智能技术飞速发展&#xff0c;尤其是大模型的出现&#xff0c;为视频理解和生成领域带来了前所未有的机遇。然而&#xff0c;现有的视频大模型&#xff08;Video-LLM&#xff09;在处理视频中复杂的时空信息和音频信息方面仍存在不足&#xff0c;例…

【C++11(二)】lambda表达式和可变参数模板

一、可变参数模板 C11的新特性可变参数模板 能够让您创建可以接受 可变参数的函数模板和类模板 // Args是一个模板参数包&#xff0c;args是一个函数形参参数包 // 声明一个参数包Args...args&#xff0c;这个参数包中可以包含0到任意个模板参数。 template <class ...Arg…