探索数据结构:深入了解顺序表的奥秘
✨✨ 欢迎大家来到贝蒂大讲堂✨✨🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:数据结构与算法
贝蒂的主页:Betty’s blog
1. 什么是顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,它与数组非常类似,但是相比于数组顺序表有一个非常明显的优点——可以动态内存增长空间大小
2. 顺序表的功能
顺序表可以大致包含以下几个功能:
初始化顺序表中的数据。
打印顺序表中的数据。
对顺序表进行尾插(末尾插入数据)。
对顺序表进行尾删(末尾删除数据)。
对顺序表进行头插(开头插入数据)。
对顺序表进行头删(开头删除数据)。
对顺序表就像查找数据。
对顺序表数据进行修改。
任意位置的删除和插入数据。
销毁顺序表。
3. 顺序表的定义
定义顺序表我们首先需要一个动态内存开辟的空间,当前数据的个数(size),以及方便扩容的容量大小(capacity)。
typedef int SLDataType; //类型重命名,方便后续修改类型
#define N 4 //初始化空间大小
typedef struct SeqList
{SLDataType* a; //指向动态开辟的数组size_t size; //有效数据个数size_t capacity; //容量大小
}SeqList;
4. 功能的具体实现
4.1 初始化顺序表
(1) 代码实现
初始化顺序表时我们可以先开辟四个空间,之后不够再进行扩容。
void SeqListInit(SeqList* p)
{assert(p); //断言p->a =(SLDataType*)malloc(N*sizeof(SLDataType)); //初始顺序表为四个空间if (p->a== NULL){perror("malloc fail:");return ;}p->size = 0; //初始数据个数为0p->capacity = 4; //初始空间容量为4
}
(2) 复杂度分析
- 时间复杂度:由于没有其他未知数的引入,所以所需时间是个常数,也就是O(1)。
- 空间复杂度:动态开辟N个空间,所以空间复杂度为O(N)。
4.2 打印数据
(1) 代码实现
打印数据只用循环打印就可以了。
void SeqListPrint(const SeqList* p)
{assert(p); //断言if (p->size == 0) //判断顺序表是否为空{printf("顺序表为空\n");return;}int i = 0;for (i = 0; i < p->size; i++) //打印顺序表{printf("%d ", p->a[i]);}printf("\n");
}
(2) 复杂度分析
- 时间复杂度:因为会打印顺序表中的所有数据,所以时间复杂度为O(N)。
- 空间复杂度:打印顺序表并不需要开辟格外的空间,所以空间复杂度为O(1)。
4.3 尾插数据
尾插数据,顾名思义就是在顺序表末尾插入数据,在插入数据之前我们应该检查顺序表是否为满。
(1) 检查是否已满
void CheckCapacity(SeqList* p)
{assert(p); //断言if (p->size == p->capacity) //检查容量,满了则增容{size_t newcapacity = 2 * p->capacity; //,扩容为原来的2倍SLDataType* prt = (SLDataType*)realloc(p->a, newcapacity * sizeof(SLDataType)); //扩容if (prt == NULL){perror("realloc fail:");return ;}p->a = prt; // prt不为空,开辟成功p->capacity = newcapacity; //更新容量}
}
(2) 插入数据
void SeqListPushBack(SeqList* p, SLDataType x)
{assert(p); //断言CheckCapacity(p); //检查顺序表容量是否已满p->a[p->size] = x; //尾插数据p->size++; //有效数据个数+1
}
(3) 复杂度分析
- 时间复杂度:没有变量影响时间,时间复杂度为O(1)。
- 空间复杂度:以最坏的情况考虑,会进行扩容,空间复杂度为O(N)。
4.4 尾删数据
同理,尾删数据就是删除顺序表中最后一个元素,我们只需将size–。注意:删除之前要保证顺序表中有数据。
(1) 代码实现
void SeqListPopBack(SeqList* p)
{assert(p); //断言assert(p->size > 0); //顺序表不能为空p->size--; //有效数据个数-1
}
(2) 复杂度分析
- 时间复杂度:没有变量影响时间,时间复杂度为O(1)。
- 空间复杂度:没有变量影响空间,空间复杂度为O(1)。
4.5 头插数据
头部插入数据就是在第一个元素位置插入一个元素。
(1) 代码实现
void SeqListPushFront(SeqList* p, SLDataType x)
{assert(p); //断言CheckCapacity(p); //检查顺序表容量是否已满int i = 0;for (i = p->size - 1; i >= 0; i--) //顺序表中[0,size-1]的元素依次向后挪动一位{p->a[i + 1] = p->a[i];}p->a[0] = x; //头插数据p->size++; //有效数据个数+1
}
(2) 复杂度分析
- 时间复杂度:因为从头部插入数据,后续数据需要依次覆盖,所以时间复杂度为O(N)。
- 空间复杂度:因为可能会进行扩容,按最坏的情况来算,空间复杂度为O(N)。
4.5 头删数据
从头部删除数据,与尾部删除数据不同,需要依次往前覆盖。
(1) 代码实现
void SeqListPopFront(SeqList* p)
{assert(p); //断言assert(p->size > 0); //顺序表不能为空int i = 0;for (i = 1; i < p->size; i++) //顺序表中[1,size-1]的元素依次向前挪动一位{p->a[i - 1] = p->a[i];}p->size--; //有效数据个数-1
}
(2) 复杂度分析
- 时间复杂度:因为需要往前覆盖数据,所以时间复杂度自然为O(N)。
- 空间复杂度:因为并没有开辟其他空间,所以空间复杂度为O(1)。
4.6 查找指定值
根据输入参数,在顺序表中查找指定的值并返回其下标,若未找到则返回-1。
(1) 代码实现
int SeqListFind(const SeqList* p, SLDataType x)
{assert(p); //断言int i = 0;for (i = 0; i < p->size; i++){if (p->a[i] == x){return i; //查找到,返回该值在数组中的下标}}return -1; //没有查找到
}
(2) 复杂度分析
- 时间复杂度:以最坏的情况分析,时间复杂度为O(N)。
- 空间复杂度:并没有格外的空间消耗,空间复杂度为O(1)。
4.7 指定位置修改
我们可以通过指定下标或者查找指定值的下标来修改任意位置的值。
(1) 代码实现
void SeqListModify(SeqList* p, int pos, SLDataType x)
{assert(p); //断言assert(p->size > 0); //顺序表不能为空assert(pos >= 0 && pos < p->size); //检查pos下标的合法性p->a[pos] = x; //修改pos下标处对应的数据
}
(2) 复杂度分析
- 时间复杂度:因为是通过指定下标修改,所以时间复杂度为O(1)。
- 空间复杂度:没有开辟额外的空间,所以空间复杂度为O(1)。
4.8 指定位置插入
和前面其他插入一样,指定位置插入也需要判断是否扩容。
(1) 代码实现
void SeqListInsert(SeqList* p, int pos, SLDataType x)
{assert(p);//断言assert(pos <= p->size); //检查pos下标的合法性SeqListCheck(p);//扩容int cur = p->size;while (cur > pos){p->a[cur] = p->a[cur - 1];//覆盖--cur;}p->a[pos] = x;p->size++;
}
(2) 复杂度分析
- 时间复杂度:需要依次覆盖,时间复杂度为O(N)。
- 空间复杂度:可能需要扩容,空间复杂度为O(N)。
4.9 指定位置删除
和前面的删除差不多,但是指定删除可能会依次覆盖。
(1) 代码实现
void SeqListErase(SeqList* p, int pos)
{assert(p); //断言assert(p->size > 0); //顺序表不能为空assert(pos >= 0 && pos < p->size); //检查pos下标的合法性int i = 0;for (i = pos + 1; i < p->size; i++) //将pos位置后面的数据依次向前挪动一位{p->a[i - 1] = p->a[i];}p->size--; //有效数据个数-1
}
(2) 复杂度分析
- 时间复杂度:需要依次覆盖,时间复杂度为O(N)。
- 空间复杂度:没有额外的空间消耗,空间复杂度为O(1)。
4.10 回收空间
在结束操作之后,需要释放开辟的空间,以防止内存泄漏。
(1) 代码实现
void SeqListDestory(SeqList* p)
{assert(p); //断言free(p->a); //释放动态开辟的空间p->a = NULL; //置空p->size = 0; //数据个数置0p->capacity = 0; //空间容量大小置0
}
(2) 复杂度分析
- 时间复杂度:没有额外的时间消耗,时间复杂度为O(1)。
- 空间复杂度:没有额外的空间消耗,空间复杂度为O(1)。
5. 完整代码
5.1 SeqList.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define N 4 //初始化空间大小
typedef int SLDataType; //类型重命名,方便后续修改类型
typedef struct SeqList
{SLDataType* a; //指向动态开辟的数组size_t size; //有效数据个数size_t capacity; //容量大小
}SeqList;void SeqListInit(SeqList* p);//初始化顺序表
void SeqListPrint(const SeqList* p);//打印顺序表
void SeqListPushBack(SeqList* p, SLDataType x);//尾插
void SeqListPopBack(SeqList* p);//尾删
void SeqListPushFront(SeqList* p, SLDataType x);//头插
void SeqListPopFront(SeqList* p);//头删
int SeqListFind(const SeqList* p, SLDataType x);//查找数据
void SeqListModify(SeqList* p, int pos, SLDataType x);//修改数据
void SeqListInsert(SeqList* p, int pos, SLDataType x);//指定插入
void SeqListErase(SeqList* p, int pos);//指定删除
void SeqListDestory(SeqList* p);//释放空间
5.2 SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
void SeqListInit(SeqList* p)
{assert(p); //断言p->a =(SLDataType*)malloc(N*sizeof(SLDataType)); //初始顺序表为四个空间if (p->a == NULL){perror("malloc fail:");return ;}p->size = 0; //初始数据个数为0p->capacity = 4; //初始空间容量为4
}
void CheckCapacity(SeqList* p)
{assert(p); //断言if (p->size == p->capacity) //检查容量,满了则增容{size_t newcapacity = 2 * p->capacity; //,扩容为原来的2倍SLDataType* prt = (SLDataType*)realloc(p->a, newcapacity * sizeof(SLDataType)); //扩容if (prt == NULL){perror("realloc");return ;}p->a = prt; // prt不为空,开辟成功p->capacity = newcapacity; //更新容量}
}
void SeqListPushBack(SeqList* p, SLDataType x)
{assert(p); //断言CheckCapacity(p); //检查顺序表容量是否已满p->a[p->size] = x; //尾插数据p->size++; //有效数据个数+1
}
void SeqListPrint(const SeqList* p)
{assert(p); //断言if (p->size == 0) //判断顺序表是否为空{printf("顺序表为空\n");return;}int i = 0;for (i = 0; i < p->size; i++) //打印顺序表{printf("%d ", p->a[i]);}printf("\n");
}
void SeqListPopBack(SeqList* p)
{assert(p); //断言assert(p->size > 0); //顺序表不能为空p->size--; //有效数据个数-1
}
void SeqListPushFront(SeqList* p, SLDataType x)
{assert(p); //断言CheckCapacity(p); //检查顺序表容量是否已满int i = 0;for (i = p->size - 1; i >= 0; i--) //顺序表中[0,size-1]的元素依次向后挪动一位{p->a[i + 1] = p->a[i];}p->a[0] = x; //头插数据p->size++; //有效数据个数+1
}
void SeqListPopFront(SeqList* p)
{assert(p); //断言assert(p->size > 0); //顺序表不能为空int i = 0;for (i = 1; i < p->size; i++) //顺序表中[1,size-1]的元素依次向前挪动一位{p->a[i - 1] = p->a[i];}p->size--; //有效数据个数-1
}
int SeqListFind(const SeqList* p, SLDataType x)
{assert(p); //断言int i = 0;for (i = 0; i < p->size; i++){if (p->a[i] == x){return i; //查找到,返回该值在数组中的下标}}return -1; //没有查找到
}
void SeqListModify(SeqList* p, int pos, SLDataType x)
{assert(p); //断言assert(p->size > 0); //顺序表不能为空assert(pos >= 0 && pos < p->size); //检查pos下标的合法性p->a[pos] = x; //修改pos下标处对应的数据
}
void SeqListInsert(SeqList* p, int pos, SLDataType x)
{assert(p);//断言assert(pos <= p->size); //检查pos下标的合法性SeqListCheck(p);//扩容int cur = p->size;while (cur > pos){p->a[cur] = p->a[cur - 1];//覆盖--cur;}p->a[pos] = x;p->size++;
}
void SeqListErase(SeqList* p, int pos)
{assert(p); //断言assert(p->size > 0); //顺序表不能为空assert(pos >= 0 && pos < p->size); //检查pos下标的合法性int i = 0;for (i = pos + 1; i < p->size; i++) //将pos位置后面的数据依次向前挪动一位{p->a[i - 1] = p->a[i];}p->size--; //有效数据个数-1
}
void SeqListDestory(SeqList* p)
{assert(p); //断言free(p->a); //释放动态开辟的空间p->a = NULL; //置空p->size = 0; //数据个数置0p->capacity = 0; //空间容量大小置0
}
相关文章:

探索数据结构:深入了解顺序表的奥秘
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:数据结构与算法 贝蒂的主页:Betty’s blog 1. 什么是顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元…...

苍穹外卖学习-----2024/03/010---redis,店铺营业状态设置
1.Redis入门 2.在Java中操作Redis 3.店铺营业状态设置 BUG!!! 今天在启动项目时,用到了Redis缓存数据库,但是却出现了报错信息: ERR Client sent AUTH, but no password is set。Caused by: io.lettuce.core.RedisCommandExecutionException…...

RUST 每日一省:发布到crates.io
github是开源代码分享的地方,rust的开源项目除了github,我们还可以将其发布到 crates.io 上,然后其它用户就可以使用cargo进行安装使用了。其实步骤很简单,只有三条命令了,我们一次来看一下。 1、cargo package 首先&a…...

String类及其常用方法
文章目录 1.String类的特性与使用1.1 String类的特性1.2 String对象的创建方式1.3 String 的使用(不同的拼接操作) 2.String常用方法2.1 String的常用方法一2.2 String常用方法二2.3 String常用方法三 1.String类的特性与使用 1.1 String类的特性 Stri…...
1094. 拼车
说在前面 🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是出于什么原因,算法学习需要持续保持。 题目描述 车上最初有 capacity 个空座位。车 只能 向一个方向行驶(也就是说,不…...

Docker进阶:深入了解容器数据卷
Docker进阶:深入了解容器数据卷 一、前言二、容器数据卷的作用三、容器数据卷的使用方法四、实战--使用docker部署前端项目(数据卷挂载)4.1 重要:准备工作,先在本地创建挂载目录4.2 启动一个临时的nginx容器࿰…...
升级版本彻底解决bootstrap-table-fixed-columns固定列后行对不齐问题
升级到bootstrap-table和bootstrap-table-fixed-columns版本都升级到v1.22.3版本以上,即可解决该问题 bootstrap-table:bootstrap-table/dist/bootstrap-table.min.css at develop wenzhixin/bootstrap-table GitHub bootstrap-table-fixed-columns&…...
打破边界:深入探索STUN在实现无缝NAT穿越和WebRTC通信中的核心作用
引言 STUN是一个网络协议,设计用于帮助在网络地址转换(NAT)后面的设备发现其公网地址和端口号。通过允许这些设备发现自己从外部看到的地址,STUN使得它们能够在NAT或防火墙背后建立端到端的通信,这对于VoIP、视频会议…...
浅谈 前端的动态绑定属性
目录 前言1. 基本知识2. Demo 前言 作为Java开发者,从开发转到全栈,前端好些细节都需要科普,这不就来个动态绑定属性 起因是这个: <uni-tr> <uni-td align"center" :rowspan"checkTypesCount 1"…...
Sklearn支持向量机
支持向量机(Support Vector Machine, SVM)是一种常用的分类算法,它可以用于解决二分类和多分类问题。在Python中,你可以使用Sklearn库来实现SVM。下面是一个简单的例子,展示了如何使用Sklearn进行SVM分类。 # 导入必要…...

【Lazy ORM】 小工具 acw 本地客户端 你负责点击页面,他负责输出代码
介绍 wu-smart-acw-client 简称acw-client,是一个基于Lazy ORM定制的客户端代码生成小工具 Lazy ORM 小工具 acw 本地客户端 你负责点击页面,他负责输出代码安装 <dependency><groupId>top.wu2020</groupId><artifactId>wu-sma…...

《详解:鸿蒙NEXT开发核心技术》
我们现在都知道鸿蒙作为一个国产的全栈自研系统,经过国家主推后。已经引起人们很大的关注,其中作为开发者来说;许多一线大厂已经与其华为鸿蒙展开原生应用的合作了,目前了解到已经有200家。而之后出现了很多的高薪鸿蒙开发岗位&am…...

快速排序 刷题笔记
思路 分治双指针 在每个区间选定一个基准目标 两个指针从数组的两边向中间推进 使用 while循环判断 do {i;}while(q[i]<x); do{j--;}while(q[j]>x); 每次这样做完就会找到q[i]>x,,,,q[j]小于x 此时我们交换 q[i] ,q[j]于是小于x的数分到了小于x的一侧 大…...

DAY by DAY 史上最全的Linux常用命令汇总----man
man是按照手册的章节号的顺序进行搜索的。 man设置了如下的功能键: 功能键 功能 空格键 显示手册页的下一屏 Enter键 一次滚动手册页的一行 b 回滚一屏 f 前滚一屏 q 退出man命令 h 列出所有功能键 /word 搜索word字符串 注意:…...

十六、接口隔离原则、反射、依赖注入
接口隔离原则、反射、特性、依赖注入 接口隔离原则 客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。 五种原则当中的i 上一章中的接口,即契约。 契约就是在说两件事,甲方说自己不会多要,乙方会在…...
Docker 进阶
1、容器数据卷 什么是容器数据卷? 就是当容器内存在了mysql,在里面书写了数据,如果容器删除了,那么数据也就没有了,通过容器数据卷的技术,可以让容器内的数据持久化到Linux服务器上 操作 #docker run -…...

科研学习|论文解读——一种修正评分偏差并精细聚类中心的协同过滤推荐算法
知网链接 一种修正评分偏差并精细聚类中心的协同过滤推荐算法 - 中国知网 (cnki.net) 摘要 协同过滤作为国内外学者普遍关注的推荐算法之一,受评分失真和数据稀疏等问题影响,算法推荐效果不尽如人意。为解决上述问题,本文提出了一种改进的聚类…...

云计算项目十一:构建完整的日志分析平台
检查k8s集群环境,master主机操作,确定是ready 启动harbor [rootharbor ~]# cd /usr/local/harbor [rootharbor harbor]# /usr/local/bin/docker-compose up -d 检查head插件是否启动,如果没有,需要启动 [rootes-0001 ~]# system…...
2.经典项目-海量用户即使通讯系统
1.实现功能-完成注册用户 完成用户注册的步骤(客户端) 1.将User移动到common/message文件夹下 2.在message中新增注册用户的结构体 const (LoginMesType "LoginMes"LoginResMesType "LoginResMes"RegisterMesType "RegisterMes"…...

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的交通标志识别系统详解(深度学习模型+UI界面代码+训练数据集)
摘要:本篇博客详细介绍了利用深度学习构建交通标志识别系统的过程,并提供了完整的实现代码。该系统采用了先进的YOLOv8算法,并与YOLOv7、YOLOv6、YOLOv5等早期版本进行了性能评估对比,分析了性能指标如mAP、F1 Score等。文章深入探…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...