【线性表】—动态顺序表的增删查改实现

news2025/2/28 17:43:04

小菜坤日常上传gitee代码:https://gitee.com/qi-dunyan(所有的原码都放在了我上面的gitee仓库里)

数据结构知识点存放在专栏【数据结构】后续会持续更新
❤❤❤
个人简介:双一流非科班的一名小白,期待与各位大佬一起努力!
推荐数据结构书籍:《大话数据结构》
在这里插入图片描述

目录

  • 前言
  • 接口实现
    • 前期准备
    • 初始化
    • 尾插与尾删
    • 打印
    • 头插与头删
    • 查找
    • 在任意位置插入与删除
    • 销毁
    • 总结

前言

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

采用数组存储的原因是,数组的地址也是连续的,随着下标的增长而增长。其实在我们之前写的通讯录,本质其实就是一个顺序表。
在这里插入图片描述

顺序表又分为静态与动态顺序表,所谓静态顺序表,就是提前开好固定大小的数组空间,而动态顺序表与之相比则更加灵活多变,因此,我们大多使用的都是动态顺序表。

在这里插入图片描述
最后,数据结构这里一定要多画图,通过图形来写代,会很容易。

接口实现

前期准备

两个源文件。分别用来测试,以及存放函数定义 一个头文件。存放函数声明与头文件包含
(另建议:有些书本上面会写菜单栏,但是为了方便调试与观察,不建议书写菜单栏)

//动态顺序表
typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;//定义一个指针指向数组
	int size;//数据数量
	int capacity;//容量
}SeqList;

初始化

这里我们来实现初始化接口,我们可以在测试文件里直接定义一个结构体,也可以定义一个结构体指针,定义结构体的话就不用再malloc结构体空间了。

接口实现:
初始化

//初始化
void SeqListInit(SeqList* ps)
{
	//断言
	assert(ps);
	//初始化
	ps->a = NULL;//指针指向空(也可以在这里直接malloc出一个空间)
	ps->size = 0;
	ps->capacity = 0;
}

尾插与尾删

尾插
在这里插入图片描述

尾插的实现非常简单,就是直接在下标为size位置处进行插入即可。唯一需要注意的就是扩容情况,即size ==
capacity时就意味着空间已满,然后就得扩容,这里由于后面的一些插入也需要进行判断扩容,所以把它写成一个check函数,后面直接调用即可。

//检查扩容
void SeqListCheck(SeqList* ps)
{
	if (ps->capacity == ps->size)
	{
		//容量为0时赋值4,每次扩容扩大2倍
		int Newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDateType* pf = (SLDateType*)realloc(ps->a, Newcapacity * sizeof(SLDateType));
		if (pf == NULL)
		{
			perror("realloc");
			return;
		}
		ps->a = pf;
		ps->capacity = Newcapacity;
	}
}

尾插

//尾插
void SeqListPushBack(SeqList* ps, SLDateType x)
{
	//断言
	assert(ps);
	//检查扩容
	SeqListCheck(ps);
	//插入数据
	ps->a[ps->size] = x;
	ps->size++;
}

尾删
我们发现,尾删也很简单,其实只需要size–,就可以实现尾删的功能了
在这里插入图片描述
但是这里需要注意的是,当顺序表为空的时候,是不能进行删除的!

//尾删
void SeqListPopBack(SeqList* ps)
{
	//断言
	assert(ps->size>0);
	ps->size--;
}

打印

这里我们写一个用来打印顺序表的函数,以便于我们用来打印观察,打印的实现也很简单,只需要打印下标从零开始,一直到 下标为size-1的即可

在这里插入图片描述

//打印
void SeqListPrint(SeqList* ps)
{
	//断言
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

这里我们在测试文件里进行测试,看一下是否有问题:

//尾插尾删
void TestSeqList1()
{
	SeqList s;//定义结构体
	//初始化
	SeqListInit(&s);
	//尾插
	SeqListPushBack(&s,1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPrint(&s); //1 2 3 4

	//尾删
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	//打印
	SeqListPrint(&s);//1 2
	//一直删到为空
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPrint(&s);//error
}

我们发现,以上是没问题的,不管是增容、还是尾删到空继续尾删,都在我们掌控之中,接下来我们进行头插与头删的操作

头插与头删

头插
顾名思义就是在数组下标为0的位置进行插入,这里我们通过画图来理解,这里头插完后记得size++
在这里插入图片描述
头插的时候切记注意检查扩容情况!

//头插
void SeqListPushFront(SeqList*ps,SLDateType x)
{
	//断言
	assert(ps);
	//检查扩容
	SeqListCheck(ps);
	int end = ps->size-1;
	//挪动数据
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	//在头部插入数据
	ps->a[0] = x;
	ps->size++;
}

头删
所谓头删,就是删除头部数据,这里还是通过覆盖的方式,画图即可更加方便理解
在这里插入图片描述
切记空表状态不可进行删除!

//头删
void SeqListPopFront(SeqList* ps)
{
	assert(ps);
	assert(ps->size > 0);
	int begain = 0;
	//挪动
	while (begain < ps->size - 1)
	{
		ps->a[begain] = ps->a[begain + 1];
		begain++;
	}
	ps->size--;
}

测试
这里通过测试发现,代码是没问题的

void TestSeqList2()
{
	SeqList s;
	SeqListInit(&s);
	//头插
	SeqListPushFront(&s, 6);
	SeqListPushFront(&s, 5);
	SeqListPushFront(&s, 4);
	SeqListPushFront(&s, 3);
	SeqListPrint(&s); // 3 4 5 6

	//头删
	SeqListPopFront(&s);
	SeqListPopFront(&s);
	SeqListPrint(&s);//5 6
	SeqListPopFront(&s);
	SeqListPopFront(&s);
	//删除空表
	SeqListPopFront(&s);
	SeqListPrint(&s);//error,报错
}

查找

顺序表查找也是一件很简单的事,从begain位置开始查找

//顺序表查找
int SeqListFind(SeqList* ps, SLDateType x,int begain)
{
	assert(ps);
	assert(begain>0&&begain<ps->size);
	//begain的位置必须在顺序表范围内(begain其实就是下标,从下标为begain位置处开始查找)
	int i = 0;
	//遍历数组进行查找
	for (i = begain; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;//找到直接返回下标
		}
	}
	//查找不到,返回-1
	return -1;
}

查找本身并不复杂,就是遍历数组而已

在任意位置插入与删除

这里还是要通过画图,能更加容易理解,另外插入的时候一定注意扩容情况!
在这里插入图片描述

还有就是,这个pos必须是在数组的有效范围内,不能跑到别的地方插入数据,因为顺序表的地址是连续的,如果超过了这个范围,就不构成连续了,如下:

在这里插入图片描述

代码实现:

//在pos位置插入
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos <= ps->size);
	//检查扩容
	SeqListCheck(ps);
	int end = ps->size - 1; 
	//挪动数据
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

任意位置删除
在这里插入图片描述
另外,pos位置也必须在有效范围内

//pos位置删除
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos <= ps->size);
	int begain = pos + 1;
	//覆盖即可
	while (begain < ps->size)
	{
		ps->a[begain - 1] = ps->a[begain];
		begain++;
	}
	ps->size--;
}

测试
在测试文件里通过数据来观察

//任意位置插入删除
void TestSeqList3()
{
	SeqList s;
	SeqListInit(&s);//初始化
	SeqListPushFront(&s, 6);
	SeqListPushFront(&s, 5);
	SeqListPushFront(&s, 4);
	SeqListPushFront(&s, 3);
	//pos位置插入
	SeqListInsert(&s, 2, 1);
	SeqListPrint(&s); // 3 4 1 5 6
	SeqListInsert(&s, 4, 1);
	SeqListPrint(&s); // 3 4 1 5 1 6
	//pos位置删除
	SeqListErase(&s, 4);
	SeqListErase(&s, 4);
	SeqListInsert(&s, 3, 4);
	SeqListPrint(&s); // 3 4 1 4 5 
}

我们发现,也是没什么问题的,说明我们已经正式写完了整个顺序表。
不过这里有一点需要注意的是,任意位置的插入与删除,如果这个位置是下标为0的地方,这就等同于头插头删,如果这个pos是在下标为size处,这就是尾插尾删
所以我们的头插可以也写为:

//头插
void SeqListPushFront(SeqList*ps,SLDateType x)
{
	断言
	//assert(ps);
	检查扩容
	//SeqListCheck(ps);
	//int end = ps->size-1;
	挪动数据
	//while (end >= 0)
	//{
	//	ps->a[end + 1] = ps->a[end];
	//	end--;
	//}
	在头部插入数据
	//ps->a[0] = x;
	//ps->size++;
	SeqListInsert(ps, 0, x);//从0位置处插入,就是头插
}

其余类比也是同理。

销毁

最后是顺序表的销毁,也很简单,释放a指向的空间,并置空a指针,然后size与capacity归零即可
这里注意,假如a是个空指针(未开辟空间就直接释放),就不能进行释放,具体原因动态内存章节已讲解,即空指针不能释放,所以加了个if判断条件。

//释放
void SeqListDestroy(SeqList* ps)
{
	//断言
	assert(ps);
	//释放空间
	if (ps->a != NULL)
	{
		free(ps->a);
		ps->a = NULL;
		ps->capacity = 0;
		ps->size = 0;
	}

}

总结

最后再总结以下,需要注意的细节地方无非是传来的参数是否为空指针,涉及到任意位置就要考虑下pos是否位置合理,还有就是只要涉及插入数据的操作,就必然要考虑到扩容,涉及到删除的操作,就必然考虑到空表问题。
最后,一定要多画图,才能更好理解!顺序表本身并不难,包括后面的链表,多画图就会很好的理解!


end
生活原本沉闷,但跑起来就会有风!❤

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

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

相关文章

【网页设计】期末大作业html+css(动漫网站)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

【机器学习项目实战10例】(十):DataCastle-租金预测

💥 项目专栏:【机器学习项目实战10例】 文章目录 一、DataCastle-租金预测二、数据集介绍三、导入相关库四、读取数据五、删除缺失值过多的列六、填补缺失数据七、特征编码八、简单跑一下九、可视化数据分布9.1 箱线图9.2 直方图和Q-Q图一、DataCastle-租金预测 本项目任务…

【ASM】字节码操作 工具类与常用类 AnalyzerAdapter 工作原理

文章目录 1.概述2.xx3.工作原理3.1初始状态3.2中间状态3.2.1顺序执行3.2.2发生跳转.2.3特殊情况: new对象3.3结束状态4.示例:打印方法的Frame4.2 编码实现5.总结1.概述 在上一篇文章: 【ASM】字节码操作 工具类与常用类 AnalyzerAdapter初步介绍 我们知道 AnalyzerAdapter 主…

Android开发java调用C简单示例

目录下载NDK和CMake新建NDK项目写入C代码&#xff0c;并运行本文使用的Android Studio版本是windows版Android Studio Bumblebee | 2021.1.1 Patch 2 先看下最终效果&#xff1a; 下载NDK和CMake 检查NDK和CMake是否已经下载了&#xff0c;这一步不难&#xff0c;具体步骤就…

工业动态界面设计 GLG Toolkit 4.2 Crack-GlgCE.4.2_x64

GLG Toolkit是为开发高级图形的动态界面而设计的框架&#xff1a;不只是简单的按钮和选单&#xff0c;而且是完全动画的图形对象&#xff0c;它能够显示动态数据和作出与用户交互的反应。它不仅是一个能够创建很多“漂亮的图片”绘图工具&#xff0c;而且它的图形引擎允许开发人…

Spring Boot 使用Docker构建运行

Docker 容器化 Spring Boot 应用 在应用容器化、容器编排大行其道的当下。今天来学习下如何使用Docker技术打包、构建、运行Spring Boot 应用程序&#xff0c;从最简单的Dockerfile开始&#xff0c;一步步的学习Docker 容器的使用过程。 Spring Boot 应用系统 创建项目 使用…

[足式机器人]Part3机构运动微分几何学分析与综合Ch02-3 平面机构离散运动鞍点综合——【读书笔记】

本文仅供学习使用 本文参考&#xff1a; 《机构运动微分几何学分析与综合》-王德伦、汪伟 《微分几何》吴大任 Ch02-3 平面机构离散运动鞍点综合2.4 鞍滑点2.4.1 鞍线与二副连架杆P-R2.4.2 鞍线误差2.4.3 三位置鞍线2.4.4 四位置鞍线2.4 鞍滑点 在平面机构运动综合时&#xff…

实验七 循环神经网络(2)梯度爆炸实验

目录6.2 梯度爆炸实验6.2.1 梯度打印函数【思考】什么是范数&#xff0c;什么是L2范数&#xff0c;这里为什么要打印梯度范数&#xff1f;6.2.2 复现梯度爆炸现象6.2.3 使用梯度截断解决梯度爆炸问题【思考题】梯度截断解决梯度爆炸问题的原理是什么&#xff1f;6.2 梯度爆炸实…

基于遗传算法的风电储能蓄电池容量优化配置matlab优化程序

基于遗传算法的风电储能蓄电池容量优化配置 风电储能蓄电池微电网配置&#xff08;基于matlab的遗传算法微电网配置优化程序&#xff09; 参考文献&#xff1a;基于遗传算法的风电储能蓄电池容量优化配置 摘要&#xff1a;为了降低独立风力发电系统中储能装置的生命周期费用&a…

【数据物语系列】 漫谈数据分布可视化分析

【数据物语系列】 漫谈数据分布可视化分析 FesianXu 20221125 at Baidu Search Team 前言 在实际工作中&#xff0c;我们经常会遇到一堆数据&#xff0c;对数据的有效分析至为关键&#xff0c;而数据的分布就是一种非常重要的数据属性&#xff0c;需要通过合适的可视化手段进行…

【创建springboot-maven项目搭建mybatis框架】(超详细)

目录 1. 创建Spring Boot项目&#xff0c;相关参数 2. 创建数据库 3. 在IntelliJ IDEA中配置Database面板 4. 添加数据库编程的依赖 5. 关于Mybatis框架 6. Mybatis编程&#xff1a;插入相册数据 1. 创建Spring Boot项目&#xff0c;相关参数 项目名称&#xff1a;csmall…

[附源码]java毕业设计中小企业人力资源管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

javaEE飞机航班信息查询网站系统

本系统主要包含了订票管理、航班信息管理、站内新闻管理、活动信息管理、用户信息管理、留言等多个功能模块。下面分别简单阐述一下这几个功能模块需求。 管理员的登录模块&#xff1a;管理员登录系统后台对本系统其他管理模块进行管理。 添加管理员模块&#xff1a;向本系统中…

UE5笔记【十】第一个蓝图项目:bluePrint。

我们将上升的斜坡或者楼梯隐藏&#xff0c;往下移动&#xff0c;使其隐藏在地面以下。然后将方块也向下移动&#xff0c;漏出一点来。我们要模拟的场景是&#xff1a;当人移动到蓝色方块上时&#xff0c;踩在方块上&#xff0c;上升的楼梯升起来。然后人可以上楼。 将蓝色方块…

HTML静态网页作业——电影介绍-你的名字 5页 无js 带音乐

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 精彩专栏推荐&#x1f4…

基于双层优化的微电网系统规划设计方法matlab程序(yalmip+cplex)

基于双层优化的微电网系统规划设计方法matlab程序&#xff08;yalmipcplex&#xff09; 参考文献&#xff1a;基于双层优化的微电网系统规划设计方法 摘要&#xff1a;规划设计是微电网系统核心技术体系之一。从分布式电源的综合优化(组合优化、容量优化)和分布式电源间的调度…

【虚幻引擎UE】UE5 两种球体绘制方法

一、网格球体绘制 center 中心点向量 segments参数越大&#xff0c;线条越多 radius是球体半径 thickness 厚度可以不用管 Depth Priority 是渲染深度可以不用管 F Life Time 是持续时间 C代码如下—— .cpp #include "drawBallFunc.h" #include "Components…

机器学习中的数学基础(二)

机器学习中的数学基础&#xff08;二&#xff09;2 线代2.1 矩阵2.2 矩阵的秩2.3 内积与正交2.4 特征值与特征向量2.5 SVD矩阵分解2.5.1 要解决的问题2.5.2 基变换2.5.3 特征值分解2.5.4 奇异值分解&#xff08;SVD&#xff09;在看西瓜书的时候有些地方的数学推导&#xff08;…

使用redis快速实现session共享,springboot

1.引入依赖 <dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId> </dependency> <!-- 引入 redis 依赖 --> <dependency><groupId>org.springframework.b…

8.2 数据结构——插入排序

1、基本思想&#xff1a;每步将一个排序的对象&#xff0c;按其关键码大小插入到前面已经排好序的一组对象的适当位置上&#xff0c;直到对象全部插入为止。即边插入边排序&#xff0c;保证子序列中随时都是有序的。 2、基本操作&#xff1a; &#xff08;1&#xff09;在有序…