探索数据结构:深入了解顺序表的奥秘
✨✨ 欢迎大家来到贝蒂大讲堂✨✨🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:数据结构与算法
贝蒂的主页: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等。文章深入探…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...

