玩转顺序表——【数据结构】

news2024/12/24 9:12:01

在C语言学习中,我们经常会遇见增删查改等一系列操作,而这些操作全都与线性表关联,没有线性表将会对这些操作完成的十分艰难!那今天就让我们来了解一下顺序表如何增删查改!!!

目录

1.线性表

2.顺序表 

2.1概念及结构

3.对顺序表的实现 

3.1创建动态内容结构体

3.2内存销毁 

 3.3判断是否需要扩容

3.4尾插

3.5头插

3.6 尾删

3.7头删

 3.8 顺序表查找

3.9 顺序表在pos位置插入x

3.10 顺序表删除pos位置的值

顺序表的问题及思考


1.线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储

 

2.顺序表 

2.1概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存 储。在数组上完成数据的增删查改。

顺序表一般可以分为:

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

 确定的数组是不能改变的

2.动态顺序表:使用动态开辟的数组存储:

通过存放一个结构体指针,使用动态内存开辟malloc函数开辟空间 ,如果空间不够用可以使用realloc函数进行扩容!

3.对顺序表的实现 

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空 间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间 大小,所以下面我们实现动态顺序表。

3.1创建动态内容结构体

typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
  SLDataType* array;  // 指向动态开辟的数组
  size_t size ;       // 有效数据个数
  size_t capicity ;   // 容量空间的大小
}SL;

array是动态内存开辟的数组指针,指向开辟的首元素地址。

size是记录存储有效内容的数据个数,方便统计。

capicity是记录容量大小,方便与size进行比较,用来判断是否需要扩容。

我们使用typedef将int重命名为SLDataType,将结构体命名为SL。

 3.2对结构体进行初始化

//第一种方法
void SeqListInit(SL* ps)
{
	ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);
	if (ps->a == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	ps->size = 0;
	ps->capacity = 4;
}
//第二种方法
void SeqListInit(SL s)
{
	s.a = NULL;
	s.size = 0;
	s.capacity = 0;
}

第二种方法是直接将结构体的内容传给函数,形参只是实参的一份临时拷贝,形参的改变不会影响实参!!!所以第二种方法是错误的!!! 

当我们使用第一种方法初始化时,我们就可以适当的开辟一点空间,如何使用malloc开辟空间在之前的博客中有所讲解http://t.csdn.cn/038La。如果开辟失败我们就直接退出程序exit(-1)。

3.2内存销毁 

在我们使用动态内存开辟后,一定要及时释放空间并置为NULL,否则会出现内存泄漏等大问题!

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

 3.3判断是否需要扩容

在顺序表的增删查改中,我们时不时需要判断存入的数据是否已满,需不需要扩容。所以我们为了方便使用此功能避免程序冗余,我们可以创建此函数用来判断开辟的内存是否需要扩容。

void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		SLDateType* p = (SLDateType*)realloc(ps->a, sizeof(ps->a) * 2);
		if (*p == NULL)
		{
			perror(realloc);
			exit(-1);
		}
		ps->capacity *= 2;
		ps->a = p;
	}
}

传入结构体指针,判断size与capacity是否相等,如果相等我们就使用realloc函数进行扩容,我们创建新指针指向新创建的空间,开辟比原来大二倍的空间。如果开辟成功我们将更新capacity的值,开辟失败直接退出程序!!!

3.4尾插

void SeqListPushBack(SL* ps, SLDateType x)
{
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

 先使用函数SLCheckCapacity进行判断是否需要进行扩容,在进行尾部插入即可。

3.5头插

将需要的数据在顺序表的头部进行插入,对于顺序表而言效率会非常低,但是我们也必须将其实现。 

void SeqListPushFront(SL* ps, SLDateType x)
{
	SLCheckCapacity(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->a[i] = ps->a[i-1];
	}
	ps->a[0] = x;
	ps->size++;
}

3.6 尾删

尾删非常的简单,我们只需要将数组往前移动一位,size--即可。我们不必担心数据问题,下次再次使用时只需要将内容覆盖即可。

void SeqListPopBack(SL* ps)
{

	assert(ps->size > 0);
	ps->size--;
}

但是在删除时我们得判断顺序表中内容是否为空,防止数组越界。我们使用assert断言函数进行判断即可。

3.7头删

头删与头插的效率都很低下,这也是顺序表的一个大缺点。基本原理与头插差不多,时间复杂度都为O(n),牵一发而动全身。

void SeqListPopFront(SL* ps)
{
	assert(ps->size > 0);
	for (int i = 0; i < ps->size-1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

删除时我们必须判断数组是否为空,防止越界。从前向后进行迭代前移进行覆盖,最后将size--即可。

 3.8 顺序表查找

为了让我们方便查找顺序表中每个内容的具体位置,然后插入想插入的数据。我们创建一个寻找下标的函数。

int SeqListFind(SL* ps, SLDateType x)
{
	assert(ps->size > 0);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
			return i;
	}
	else
		return -1;
}

我们使用暴力查找法,将数组遍历一遍,如果能找到则返回其下标,如果找不到则返回-1结束。 

3.9 顺序表在pos位置插入x

我们使用3.8中的函数,将需要插入位置找到,然后使用此函数将其插入到顺序表中。

void SeqListInsert(SL* ps, int pos, SLDateType x)
{
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}

中间插入,前面的数据不需要移动,在pos后的位置要向后移动。

3.10 顺序表删除pos位置的值

void SeqListErase(SL* ps, int pos)
{
	assert(ps->size > 0);
	for (int i = pos - 1; i < ps->size-1; i++)
	{
		ps->a[i] = pos->a[i + 1];
	}
	ps->size--;
}

与插入原理相同,pos后的内容向前一位即可。

顺序表的问题及思考

问题:

1. 中间/头部的插入删除,时间复杂度为O(N)

2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。

3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

思考:如何解决以上问题呢?下面给出了链表的结构来看看。

我们可以使用链表解决以上问题,下一期我们将走进链表章节。

欲知后事如何,尽情期待下一期!!! 

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

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

相关文章

(二)Spring WeFlux响应式编程第二种整合方案|道法术器

Spring WebFlux 响应式异步编程|道法术器(一) Spring WeFlux响应式编程整合另一种方案|道法术器(二) R2dbc操作mysql 注意下面红色部分与上一篇"Spring WebFlux 响应式异步编程|道法术器(一)" 不一样的依赖包 技术整合: <!--设置spring-boot依赖的版本 --> &l…

Vault数据备份恢复-MySQL

前言 Vault提供了可靠的功能来保护数据库和其他关键数据。 对于MySQL数据库,Vault提供了一个易于使用的解决方案,可以自动创建和管理定期备份,并支持从备份中快速恢复数据。本文将介绍Vault后端存储MySQL的备份恢复,包括如何设置Vault、如何进行数据备份和还原、如何保护…

【K210视觉模块】内存报错问题

一、正常的打开CanMV IDE 连接 运行测试多次&#xff0c;出现如下报错 报错1&#xff1a;Memory Error: 模型缓冲区内存分配失败 报错2&#xff1a;MemoryError:超出正常MicroPython堆内存!请降低您正在运行此算法的图像的分辨率以绕过此问题! 二、解决方法 重新烧录固件库 …

【Python】pyqt6入门到入土系列,非常详细...

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 一、什么是PyQt6? 简单介绍一下PyQt6 1、基础简介 PyQt6 Digia 公司的 Qt 程序的 Python 中间件。Qt库是最强大的GUI库之一。 PyQt6的官网&#xff1a;www.riverbankcomputing.co.uk/news。 PyQt6是由Riverbank Co…

Windows本地安装配置Qcadoo MES系统

简介 Qcadoo MES是一款功能强大且灵活的开源MES&#xff08;制造执行系统&#xff09;&#xff0c;旨在为制造业务提供全面的管理和监控解决方案。本篇博客将教您如何在Windows操作系统上安装和配置Qcadoo MES系统&#xff0c;以便您能够轻松管理和监控制造过程。 环境要求 …

java 数组的使用

数组 基本介绍 数组可以存放多个同一类型的数据&#xff0c;数组也是一种数据类型&#xff0c;是引用类型。 即&#xff1a;数组就是一组数据。 数组的使用 1、数组的定义 方法一 -> 单独声明 数据类型[] 数组名 new 数据类型[大小] 说明&#xff1a;int[] a new int…

GFS分布式文件系统概述以及集群部署

目录 一、GlusterFS简介 二、GlusterFS特点 2.1 扩展性和高性能 2.2 高可用性 2.3 全局统一命名空间 2.4 弹性卷管理 2.5 基于标准协议 三、GlusterFS术语 四、模块化堆栈式架构 五、GlusterFS 的工作流程 六、弹性 HASH 算法 七、GFS支持的七种卷 7.1 分布式卷&…

iOS——锁与死锁问题

iOS中的锁 什么是锁锁的分类互斥锁1. synchronized2. NSLock3. pthread 递归锁1. NSRecursiveLock2. pthread 信号量Semaphore1. dispatch_semaphore_t2. pthread 条件锁1. NSCodition2. NSCoditionLock3. POSIX Conditions 分布式锁NSDistributedLock 读写锁1. dispatch_barri…

安全人员爱用的12款开源渗透测试工具

回顾过去&#xff0c;黑客入侵异常困难&#xff0c;需要大量手动操作。然而&#xff0c;如今&#xff0c;一套自动化测试工具让渗透测试人员变身“半机械人”&#xff0c;能够比以往任何时候都更轻松地完成更多测试。以下12款开源渗透测试工具&#xff0c;可以帮助渗透测试人员…

JMeter发送get请求并分析返回结果

在实际工作的过程中&#xff0c;我们通常需要模拟接口&#xff0c;来进行接口测试&#xff0c;我们可以通过JMeter、postman等多种工具来进行接口测试&#xff0c;但是工具的如何使用对于我们来说并不是最重要的部分&#xff0c;最重要的是设计接口测试用例的思路与分析结果的能…

Gis入门,根据起止点和一个控制点计算二阶贝塞尔曲线(共三个控制点组成的线段转曲线)

前言 本章讲解如何在gis地图中使用起止点和一个控制点(总共三个控制点)生成二阶贝塞尔曲线。 三阶贝塞尔曲线请参考下一章《Gis入门,使用起止点和两个控制点生成三阶贝塞尔曲线(共四个控制点)》 贝塞尔曲线(Bezier curve)介绍 贝塞尔曲线(Bezier curve)是一种数学…

pyqt5:PyCharm中找不到External-tools解决办法

使用pyqt时会使用到PYUIC&#xff0c;晚上很多教程直接说在External-tools里使用就行&#xff0c;但是很多初始情况是没有的(但是有的就直接有&#xff0c;玄学~)&#xff0c;这篇文章介绍下找不到External-tools的时候怎么配置&#xff0c;这个找不到意思是下面&#xff1a; …

两级运算放大器设计与仿真

两级运算放大器的设计与仿真 0.两级运算放大器的设计步骤 运算放大器&#xff08;简称运放&#xff09;是许多模拟系统和混合信号系统中的一个完整部分。各种不同复杂程度的运放被用来实现各种功能&#xff1a;从直流偏置的产生到高速放大或滤波。伴随者每一代 CMOS 工艺&…

linux-安全技术

文章目录 安全机制墨菲定理信息安全防护的目标安全防护环节常见的安全攻击STRIDE 安全机制 墨菲定理 摘自百度百科 墨菲定律是一种心理学效应&#xff0c;1949年由美国的一名工程师爱德华墨菲&#xff08;Edward A. Murphy&#xff09;提出的&#xff0c;亦称墨菲法则、墨菲…

Robot Framweork之UI自动化测试---Selenium2Library常用关键字

在项目实际自动化测试过程中&#xff0c;主要用到了Selenium2Library库里的一些关键字和内置包BuiltIn的关键字&#xff0c;今天我们就来分享下Selenium2Library常用关键字。 我们把操作主要分为六大类&#xff1a; 一&#xff09;浏览器操作 二&#xff09;文本输入 三&…

RealEvo-SylixOS-Installer简介

RealEvo-SylixOS-Installer简介 RealEvo-SylixOS-Installer 是 RealEvo-IDE 提供的一个安装工具&#xff0c;只需几个简单的配置&#xff0c;就可以将 SylixOS 系统安装到指定的U盘或者磁盘上&#xff0c;这极大地方便了 SylixOS 操作系统在 x86 平台的安装。 如下图所示&…

Charlotte:完全不会被检测到的Shellcode启动器

关于Charlotte Charlotte是一款基于C实现的Shellcode启动器&#xff0c;并且完全不会被安全解决方案所检测到。 工具特性 截止至2021年5月13日之前&#xff0c;该工具的检测结果为0/26&#xff1b; 该工具支持动态调用Win32 API函数&#xff1b; 对Shellcode和函数名进行异…

APP外包开发的iOS开发框架

在开发APP时需要用到各种框架&#xff0c;这些框架提供了基础的软件功能&#xff0c;可以减轻开发工作量&#xff0c;因此在APP项目开发中熟练运用常见的框架是开发者需要掌握的技能。每个框架都有其特点和适用场景&#xff0c;开发者可以根据项目的需求选择合适的框架进行开发…

HTTP协议 和 HTTPS协议的区别(4点) HTTPS的缺点 HTTP如何使用SSL/TLS协议加密过程 CA证书干啥的

&#xff08;一&#xff09;HTTP协议 和 HTTPS协议的区别&#xff08;4点&#xff09;&#xff1a; 1. HTTP协议的端口号是80&#xff0c; HTTPS协议的端口号是443 2. HTTP协议使用的URL是以 http:// 开头&#xff0c;HTTPS协议使用的URL是以https://开头 3. HTTP协议和HTTP…

steam搬砖项目有哪些坑,新手零基础入门之前一定要知道的

首先&#xff0c;先说大家最最关心的问题&#xff0c;就是这个Steam搬砖项目的利润。这个项目呢这并不是一个暴利项目&#xff0c;每次交易通常需要经历7天的饰品冷却期以及2到4天的交易时间。其次&#xff0c;为什么我们要分享这个赚钱项目呢&#xff1f;首先&#xff0c;这个…