【数据结构】顺序表详解

news2025/1/19 23:09:04

本章要分享到内容是数据结构线性表的内容,那么学习他的主要内容就是对数据的增删查改的操作。

以下为目录方便阅读

目录

1.线性表中的顺序表和顺序表

2.顺序表

2.1概念和结构

2.2动态顺序表使用场景


比如我们看到的所显示出来的群成员的列表这样所展示出来的数据。

同时呢我们也可以对里面的成员内容进行操作

 右击一个成员你就可以看到一些可以操作的内容,比如移除群聊;当然我们如果想邀请别人加入群聊的话也是对这个表里的内容进行操作,同样的输入关键字也可以找到这个表中对应的内容所以这就是数据在我们以后的业务中涉及到的一些增删查改的问题。

1.线性表中的顺序表和顺序表

首先要说的是顺序表,顺序表的本质上就是数组,怎么就是数组了呢?

给大家上图演示一下

 竖着可能不太好理解,但是这样横着放应该比较容容易理解一些,这样就和我们平时学习的数组没什么区别。

但是数组是有一些缺陷的, 比如说我想将上面的其中一个成员删掉,用数组来做还是有点困难的。在我们平时的学习中,在数组中删除掉其中一个数据,也可以理解为释放掉数组中的一块空间是做不到的,释放空间只能释放掉这个整体,所以顺序表想要做到增删是非常困难的。

我们想要删除内容的本质是挪动数据覆盖,也就是说将后面的数据向前一个一个的挪动,将想要删除的人的数据覆盖掉,就相当于完成了删除的操作。

那数组在增删这方面是有缺陷的,有没有什么好的方法可以弥补数组的缺陷呢?

所以有一种存储方式叫做链表,链表就是一小块一小块的空间,不是一个完整的连续的空间。

相对于顺序表中指针指向第一块空间,就可以找到后面所有的空间,链表却做不到这些。

因为链表中的空间是一块一块的,是多次使用malloc函数开辟出来的,他们的地址之间没有关联。

那地址之间没有关系是怎么连接起来的呢?

链表通过下一个空间内容中存放上一个空间的指针,下一个空间内容中存放上一个空间的指针,循环往复就将一小个空间连接了起来

 假如我们想要将上图中第二个内容删除,我们可以直接free释放掉其内容(空间是malloc出来的),然后让第三个空间存放第一个空间的地址即可(因为第二个空间的内容已经被删除掉,无需再存放其地址),无需 再挪动数据。

所以用数组挪动数据就非常的费劲,使用链表就会轻松很多。

那既然数组增删时这么难受为什么还要学习数组呢?

虽然数组再增删时非常的费劲,但是数组的好处就是可以随机访问下标, 可以随机访问下标的好处就是可以使用二分查找以及其他的查找方法查找数据,反观二分查找却不能在链表上使用,因为链表的地址时不连续的。

 所以这就是我们为什么要学习数据结构,不同的储存方式有不同的使用场景,根本不存在一种结构就可以包含各种结构的优点,了解得更多我们便可以在以后的业务中使用的得心应手。 

接下来要更深入的了解顺序表表

2.顺序表

2.1概念和结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。其实顺序表对数组还是有要求的,不是在数组中随意存储,必须是连续存储。

数据表一般分为两种:静态数据表和动态数据表 

静态顺序表

#define N 10
typedef int SLDatatype;

struct Seqlist
{
	SLDatatype a[N];
	int size;//存储的有效数据个数
};

以上就是一个简单的静态顺序表,为了方便修改数组空间我们不妨使用宏定义;为了方便修改数据我们不妨用typedef替换,应该不难看懂。

静态顺序表的缺点就是它的空间时固定的,我们如果想存放十一个数据就会无法存储,也就是说在存储数据时,空间给小了不够用,给多了又用不上,达不到我们想要的效果,在业务中也很少使用。

动态顺序表

//动态顺序表
typedef int SLDatatype;
struct Seqlist
{
	SLDatatype* a;// 指向动态开辟的数组
	int size;//存放数据的有效个数
	int capacity;//容量
};

和静态顺序表稍微有些不同,动态顺序表要使用malloc开辟空间。定义了一个指针让其指向动态开辟的数组。

2.2动态顺序表使用场景

接下来实现两个简单的使用场景,分别是初始化和释放空间。

void SLInit(SL sl);
void SLDestory(SL sl);

我们简单的实现一下这两个函数。

首先是初始化函数

void SLInit(SL sl)
{
	sl.a = NULL;
	sl.capacity = 0;
	sl.size = 0;
}

这里采用的方式是手动的将其内容都将成员初始化成0。

然后再用main函数调用函数,代码如下

#include"Seqlist.h"
int main()
{
		SL s;
		s.a = NULL;
		SLInit(s);
		return 0;
}

但是我们要注意的是,不可以直接再SLInit中的参数直接传值过去

我们调试观察一下

我们观察到虽然我们调用了SLInit自定义初始化函数来初始化结构体s,但是我们发现s中的值并没有像sl中的值被初始化,s中的值还是一堆乱糟糟的。

所以以上错误例子指出我们要在给结构体传参的时候要传地址,而不是传值 。

那接下来我们使用传址的方式看能不能初始化结构体s;

int main()
{
		SL s;
		s.a = NULL;
		SLInit(&s);

		return 0;
}

只需要给参数的前面加上&,就会结构体s的地址

同样的,函数中的参数也需要变成一个指针类型来接收这个参数,当然内容也要从改变值变为改变成员的地址,以下是修改后的的SLInit

void SLInit(SL* psl)
{
	psl->a = (SLDatatype*)malloc(sizeof(SLDatatype)*4);
	if (psl->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	psl->capacity = 4;
	psl->size = 0;
}

可以看出我们使用了指针变量来初始化这个结构体的成员变量,注意也不要忘记开辟空间时要判断开辟空间是否成功。

那么SLDestory的实现就非常简单,我们只需要将使用过的空间释放掉就好了,代码如下

void SLDestory(SL* psl)
{
	free(psl->a);
	psl->a = NULL;
	psl->size = 0;
	psl->capacity = 0;
}

。 

接下来加一点难度,我们使用顺序表来在顺序表的末尾添加数据,我们不妨定义一个函数名为SLPushBack的函数来解决这样的问题。

在写函数内容之前我们要明确思路怎么样才能实现尾部插入呢?

观察下图你就会发现

 siz在上图中的意义是有效的数据个数,也可以理解成最后一个数据,我们只要通过访问size的下标就能知道最后一位在哪儿,所以我想插入数据只用在size的位置插入即可。

下面用代码来实现

void SLPushback(SL* psl, SLDatatype x)
{
	psl->a[psl->size] = x;
	psl->size++;
}

参数有两个,第一个是我们想要操作的结构体,第二个参数就是我们想要加入的数字;

根据上图的描述我们知道psl要指向在a数组中size所在的位置,添加完后继续访问后面的空间来插入数据。

但是上图中我们发现最多再添加两个数据这个顺序表的空间就满了,所以我们不妨再检查一下这个数据表的容量。考虑到以后还要使用到检查空间,我我们不妨将检查空间这个步骤写成一个函数CheckCapacity,一劳永逸。

void SLCheckCapacity(SL* psl)
{
	if (psl->size == psl->capacity)
	{
		SLDatatype* tmp = (SLDatatype*)realloc(psl->a, sizeof(SLDatatype) * psl->capacity * 2);
		if (tmp == NULL)
		{
			perror("relloc fail");
			return;
		}
		psl->a = tmp;
		psl->capacity *= 2;
	}
}

 既然要扩容,我们就得先判断一下原先的空间是否被塞满,不妨使用if语句,判断有效数据个数和容量空间的大小是否相等,如果相等的话就得使用realloc来调整所开辟的空间的大小,最好是开辟原本空间两倍的大小,以防止小了不够用,大了用不上的问题,同样的还要判断开辟空间是否成功。

如果开辟空间成功我们就将新空间tmp重新赋给a

这就是检查数据表中的容量。

我们不妨将整个过程验证一下,将输入的数字都打印出来,不妨写一个打印函数来遍历我们的数据

void SLPrint(SL* psl)
{
	for (int i = 0; i < psl->size; i++)
	{
		printf("%d ", psl->a[i]);
	}
}

同时我们要在main函数中添加数据

#include"Seqlist.h"
int main()
{
	SL s;
	s.a = NULL;
	SLInit(&s);
	SLPushback(&s, 1);
	SLPushback(&s, 2);
	SLPushback(&s, 3);
	SLPushback(&s, 4);
	SLPushback(&s, 5);
	SLPushback(&s, 6);
	SLPrint(&s);
	SLDestory(&s);

	return 0;
}

 可以看到我们上面所写的函数都发挥了作用,我们刚开始只有四个空间,那么就是说第五个数据就会扩容

以上就是顺序表的简单的使用,如果对你有帮助,还请三连支持,感谢您的阅读

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

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

相关文章

Java——重建二叉树

题目链接 重建二叉树 题目描述 给定节点数为 n 的二叉树的前序遍历和中序遍历结果&#xff0c;请重建出该二叉树并返回它的头结点。 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建出如下图所示。 题目示例 示例1 输入&…

RK3568平台开发系列讲解(驱动基础篇)V4L2 用户空间 API 说明

🚀返回专栏总目录 文章目录 一、V4L2 用户空间 API二、打开视频设备三、查询设备功能沉淀、分享、成长,让自己和他人都能有所收获!😄 📢设备驱动的主要目的是控制和利用底层硬件,同时向用户展示功能。 这些用户可以是在用户空间或其他内核驱动中运行的应用。 本篇我们…

KIOPTRIX: LEVEL 5通关详解

环境配置 虚拟机网络适配器删了重新上一个就行 信息收集 漏洞发现 两个端口的web页面都没有显著的特征,尝试扫描路径,也没有扫到有价值的信息 8080端口访问被拒绝 在80端口的web页面源码中发现信息 访问 注意到title是pChart 尝试利用 可以知道有目录穿越和xss 我们可以尝…

Java实现根据利润提成发放的奖金,求1感叹号+2感叹号+……+20的和这两个程序的代码

目录 前言 一、根据利润提成发放的奖金 1.1运行流程&#xff08;思想&#xff09; 1.2代码段 1.3运行截图 二、求1!2!3!……20的和 1.1运行流程&#xff08;思想&#xff09; 1.2代码段 1.3运行截图 前言 1.因多重原因&#xff0c;本博文有两个代码程序组成&#xff…

游戏工厂:AIGC/ChatGPT与流程式游戏开发(码客 卢益贵)

关键词&#xff1a;AI&#xff08;AIGC、ChatGPT、文心一言&#xff09;、流程式管理、好莱坞电影流程、电影工厂、游戏工厂、游戏开发流程、游戏架构、模块化开发 一、前言 开发周期长、人工成本高、成功率低等是游戏公司融资困难的罪因。所以有的公司凭一个爆款游戏一骑绝尘…

比GPT-4 Office还炸裂,阿里版GPT全家桶来袭

疯狂3月的那一天&#xff0c;一切还历历在目。 微软突然在发布会上放出大招&#xff0c;用Microsoft 365 Copilot掀起了办公软件革命。 而今天&#xff0c;阿里也放出一枚重磅炸弹——阿里版的Copilot也要来了&#xff01; 并且比微软更彻底的是&#xff0c;阿里全系产品也都…

“我用 ChatGPT 造了一个零日漏洞,成功逃脱了 69 家安全机构的检测!”

一周以前&#xff0c;图灵奖得主 Yoshua Bengio、伯克利计算机科学教授 Stuart Russell、特斯拉 CEO 埃隆马斯克、苹果联合创始人 Steve Wozniak 等在内的数千名 AI 学者、企业家联名发起一则公开信&#xff0c;建议全球 AI 实验室立即停止训练比 GPT-4 更强大的模型&#xff0…

Python高级编程 type、object、class的区别 python中常见的内置类型 魔法函数

python中一切皆对象 代码块&#xff1a; a 1 print(type(a)) print(type(int))控制台输出&#xff1a; <class int> <class type>也就是说在python中int类是由type类生成的&#xff0c;而数字1是由int类生成的。 代码块&#xff1a; b "abc" prin…

SHELL函数可课后作业

一、题目 1、编写函数&#xff0c;实现打印绿色OK和红色FAILED 判断是否有参数&#xff0c;存在为Ok&#xff0c;不存在为FAILED 2、编写函数&#xff0c;实现判断是否无位置参数&#xff0c;如无参数&#xff0c;提示错误 3、编写函数实现两个数字做为参数&#xff0c;返回最…

Window中,Visual Studio 2022(C++)环境下安装OpenCV教程(不用Cmake版本)

Window中&#xff0c;Visual Studio 2022(C)环境下安装OpenCV教程 本教程主要为了方便小白安装C版本的OpenCV。 1. 第一步&#xff1a;下载官方OpenCV 下载后&#xff0c;在本地安装即可&#xff0c;注意记住安装路径&#xff0c;后续需要&#xff01; 2. 配置系统环境变量…

人口普查数据集独热编码转换

人口普查数据集独热编码转换 描述 在机器学习中&#xff0c;数据的表示方式对于模型算法的性能影响很大&#xff0c;寻找数据最佳表示的过程被称为“特征工程”&#xff0c;在实际应用中许多特征并非连续的数值&#xff0c;比如国籍、学历、性别、肤色等&#xff0c;这些特征…

中国版ChatGPT来了!快跟我一起申请文心一言吧

随着ChatGPT的快速进化吸引了全球网友的眼球 国内厂商也纷纷推出了相似的产品 其中百度推出的“文心一言”已经正式开始的相关的测试 很多人都在问 文心一言入口在哪&#xff1f; 文心一言邀请码在哪可以领&#xff1f; 文心一言怎么申请内测&#xff1f; 自从文心一言发…

手把手教你搭建自己本地的ChatGLM

前言 如果能够本地自己搭建一个ChatGPT的话&#xff0c;训练一个属于自己知识库体系的人工智能AI对话系统&#xff0c;那么能够高效的处理应对所属领域的专业知识&#xff0c;甚至加入职业思维的意识&#xff0c;训练出能够结合行业领域知识高效产出的AI。这必定是十分高效的生…

ChatGPT本地部署(支持中英文,超级好用)!

今天用了一个超级好用的Chatgpt模型——ChatGLM&#xff0c;可以很方便的本地部署&#xff0c;而且效果嘎嘎好&#xff0c;经测试&#xff0c;效果基本可以平替内测版的文心一言。 目录 一、什么是ChatGLM&#xff1f; 二、本地部署 2.1 模型下载 2.2 模型部署 2.3 模型运…

HCIE 第一天防火墙笔记整理

一、结合以下问题对当天内容进行总结 1. 什么是防火墙&#xff1f; 2. 状态防火墙工作原理&#xff1f; 二、复现上课俩个演示实验 一、结合以下问题对当天内容进行总结 1 什么是防火墙&#xff1f; 防火墙是一种隔离&#xff08;非授权用户和授权用户之间部署&#xff09;并过…

大数据学习完可以做什么

如果要推荐一种人人都能掌握的编程语言&#xff0c;应该没有比Python更合适的了。如果想学习大数据&#xff0c;可以选择从python语言入手~ Python 简单易学&#xff0c;用途广泛&#xff0c;不仅可以在日常办公中提高大家的职场效率&#xff0c;还能被大型互联网企业应用于后…

C++-c语言词法分析器

一、运行截图 对于 Test.c 的词法分析结果 对于词法分析器本身的源代码的分析结果 二、主要功能 经过不断的修正和测试代码&#xff0c;分析测试结果&#xff0c;该词法分析器主要实现了以下功能&#xff1a; 1. 识别关键字 实验要求&#xff1a;if else while do for main…

常见排序算法

目录 一、插入排序 1、直接插入排序 2、希尔排序(缩小增量插入排序&#xff09; 二、选择排序 三、堆排序 四、冒泡排序 五、快速排序&#xff08;递归&#xff09; 1、交换法 2、挖坑法 3、前后指针法&#xff08;推荐&#xff09; 4、快排再优化 六、快速排序&…

spring常用注解(全)

一、前言 Spring的一个核心功能是IOC&#xff0c;就是将Bean初始化加载到容器中&#xff0c;Bean是如何加载到容器的&#xff0c;可以使用Spring注解方式或者Spring XML配置方式。 Spring注解方式减少了配置文件内容&#xff0c;更加便于管理&#xff0c;并且使用注解可以大大…

Vue学习笔记(6. 组件之间传值)

1. 组件基本语法 (1) template (2) script (3) style 2. 父组件传值&#xff0c;子组件接值 (1) 父组件传值给子组件 (2) 子组件接收父组件的传值&#xff08;随时接收&#xff09; 子组件的值会随着父组件值的变更而变更。但是子组件变更&#xff0c;不会影响父组件的数据…