数据结构:顺序表的奥秘

🎉个人名片:
🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🐻❄个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🕊系列专栏:零基础学习C语言----- 数据结构的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉
————————————————
🎉文章简介:
🎉本篇文章对 用C语言实现顺序表 学习的相关知识进行分享!🎉
如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加油,一起奔跑,让我们顶峰相见!!!🎉🎉🎉
目录
一.顺序表的概念及存储结构
1.1储存结构
二.顺序表的实现
一.功能函数的实现
1.初始化函数
2.顺序表的销毁
3.顺序表的打印
4.扩容函数
5.尾插函数
6.尾删函数
7.头插函数
8.头删函数
9.插入函数
10.删除函数
11.查找函数
12.修改函数
三.总代码
四.顺序表的性能分析
一.顺序表的概念及存储结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表可以分为静态顺序表和动态顺序表。
1.1储存结构
静态顺序表:使用定长数组存储元素;

动态顺序表:数组的大小是根据存储的数据个数,如果满了就动态开辟出来的,相对而言不会造成空间的浪费;

二.顺序表的实现
静态顺序表 只适用于确定知道需要存多少数据的场景;
静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。例如:如果数组的大小定为200,却只储存了几十个数据,和动态的顺序表相比,空间浪费更大;所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
一.功能函数的实现(含图解)
1.初始化函数
功能:对结构体内成员进行初始化操作;
代码实现:
void InitList(SL* s)
{assert(s); //断言,防止传入空指针s->a = (SLDateType* )malloc(sizeof(SLDateType) * 4); if (s->a == NULL) //这里最开始开辟四个存储数据类型的大小{perror("malloc fail");exit(-1);}s->size = 0; //存储的有效数据个数为0s->capacity = 4; //空间置成4
}
2.顺序表的销毁
功能:对动态开辟的空间进行销毁,空间释放
代码实现:
void DestoryList(SL* s)
{assert(s);free(s->a); //释放动态开辟的空间s->a = NULL; //置空s->capacity = s->size = 0;
}
3.顺序表的打印
代码实现:
void SListPrintf(SL* s)
{assert(s);if (s->size < 0) //如果没有数据,则直接返回{return;}for (int i = 0; i < s->size; i++){printf("%d ", s->a[i]); //遍历依次打印}printf("\n"); //打印完换行
}
4.扩容函数
功能:检查是否需要扩容
代码实现:
void CheckCapacity(SL* s)
{assert(s);if (s->capacity == s->size) //相等则说明空间已经满了{SLDateType* tmp = realloc(s->a, sizeof(SLDateType)* 2 * s->capacity); //二倍扩容if (tmp == NULL) {perror("realloc fail");exit(-1);}s->a = tmp;s->capacity *= 2;}
}
5.尾插函数
功能:在顺序表最后插入一个数据
代码实现:
void PushBack(SL* s, SLDateType n)
{assert(s);CheckCapacity(s); //检查空间是否满s->a[s->size] = n; //直接插入到数组最后s->size++; //有效数据个数++
}
6.尾删函数
功能: 删除顺序表的最后一个数据
代码实现:
void PopBack(SL* s)
{assert(s);assert(s->size > 0); //当数组中有效数据个数为0时,不能再删除s->size--; //数据个数--}
7.头插函数
功能:在顺序表最前面插入一个数据
代码实现:
void PushFront(SL* s, SLDateType n)
{assert(s);CheckCapacity(s); //检查扩容int end = s->size; while (end>0) {s->a[end] = s->a[end - 1]; //挪动数据end--;}s->a[0] = n; s->size++;
}
图解:

性能分析:头插一个数据,首先需要将全部数据一次往后挪一个位置,时间复杂度:O(N)
是在原数组上进行挪动的,空间复杂度:O(1)
8.头删函数
功能:删除表中第一个元素
代码实现:
void Popfront(SL* s)
{assert(s);assert(s->size > 0); //size为0时,不能再删除for (int i = 0; i < s->size; i++){s->a[i] = s->a[i+1]; //向前挪动数据}s->size--;
}
图解:

性能分析:头删一个数据,首先需要将全部数据一次往前挪一个位置,将第一个元素覆盖掉,时间复杂度:O(N)
是在原数组上进行挪动的,空间复杂度:O(1)
9.插入函数
功能:在某个位置插入一个数据
代码实现:
void SListInsert(SL* s, int pos, SLDateType n)
{assert(s);assert(pos >= 0 && pos <= s->size); //判断pos合法int end = s->size;int begin = pos;while (begin < end){s->a[end] = s->a[end - 1]; //挪动数据end--;}s->a[pos] = n; //修改数据s->size++;
}
图解:

性能分析:中间插入一个数据和头插差不多,首先需要将该位置后面的全部数据依次往后挪一个位置,将该位置空出来,再将该数据插入,时间复杂度:O(N)
是在原数组上进行挪动的,空间复杂度:O(1)
10.删除函数
功能:删除数组中任何位置的数据
代码实现:
void SListErase(SL* s, int pos)
{assert(s);assert(pos >= 0 && pos < s->size); //pos范围合法判断int cur = pos;while (cur < s->size){s->a[cur] = s->a[cur+1]; //挪动位置cur++;}s->size--;}
图解:

性能分析:删除一个数据与头删差不多,首先需要待删数据位置后面全部数据依次往前挪一个位置,将待删元素覆盖掉,时间复杂度:O(N)
是在原数组上进行挪动的,空间复杂度:O(1)
11.查找函数
功能:查找顺序表中某个数据,返回下标
代码实现:
int SListFind(SL* s,SLDateType n)
{assert(s);for (int i = 0; i < s->size; i++) //遍历寻找{if (s->a[i] == n) //找到了返回下标{ return i;}}printf("顺序表中无该数据\n"); exit(-1);}
性能分析:将数组中的数据遍历一遍;时间复杂度:O(N)
空间复杂度:O(1)
12.修改函数
功能:修改数组中某个数据
代码实现:
void SListModify(SL* s, int pos,SLDateType n)
{assert(s);assert(pos >= 0 && pos < s->size);s->a[pos] = n; //直接通过下标访问修改
}
三.总代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int SLDateType;struct SeqList
{SLDateType* a; //指向一个数组的指针int size; //记录数据个数int capacity; //记录容量,如果与数据个数相等就扩容
};typedef struct SeqList SL;void InitList(SL* s);void SListPrintf(SL* s);void PushBack(SL* s, SLDateType n);
void PushFront(SL* s, SLDateType n);
void PopBack(SL* s);
void Popfront(SL* s);int SListFind(SL* s,SLDateType n);void SListModify(SL* s, int pos, SLDateType n);
void SListErase(SL* s, int pos);
void SListInsert(SL* s, int pos, SLDateType n);void DestoryList(SL* s);
#include"SeqList.h"void InitList(SL* s)
{assert(s); //断言,防止传入空指针s->a = (SLDateType* )malloc(sizeof(SLDateType) * 4); if (s->a == NULL) //这里最开始开辟四个存储数据类型的大小{perror("malloc fail");exit(-1);}s->size = 0; //存储的有效数据个数为0s->capacity = 4; //空间置成4
}void SListPrintf(SL* s)
{assert(s);if (s->size < 0) //如果没有数据,则直接返回{return;}for (int i = 0; i < s->size; i++){printf("%d ", s->a[i]); //遍历依次打印}printf("\n"); //打印完换行
}void CheckCapacity(SL* s)
{assert(s);if (s->capacity == s->size) //相等则说明空间已经满了{SLDateType* tmp = realloc(s->a, sizeof(SLDateType)* 2 * s->capacity); //二倍扩容if (tmp == NULL) {perror("realloc fail");exit(-1);}s->a = tmp;s->capacity *= 2;}
}void PushBack(SL* s, SLDateType n)
{assert(s);CheckCapacity(s); //检查空间是否满s->a[s->size] = n; //直接插入到数组最后s->size++; //有效数据个数++
}void PushFront(SL* s, SLDateType n)
{assert(s);CheckCapacity(s); //检查扩容int end = s->size; while (end>0) {s->a[end] = s->a[end - 1]; //挪动数据end--;}s->a[0] = n; s->size++;
}void PopBack(SL* s)
{assert(s);assert(s->size > 0); //当数组中有效数据个数为0时,不能再删除s->size--; //数据个数--}void Popfront(SL* s)
{assert(s);assert(s->size > 0); //size为0时,不能再删除for (int i = 0; i < s->size; i++){s->a[i] = s->a[i+1]; //向前挪动数据}s->size--;
}int SListFind(SL* s,SLDateType n)
{assert(s);for (int i = 0; i < s->size; i++) //遍历寻找{if (s->a[i] == n) //找到了返回下标{ return i;}}printf("顺序表中无该数据\n"); exit(-1);
}void SListModify(SL* s, int pos,SLDateType n)
{assert(s);assert(pos >= 0 && pos < s->size);s->a[pos] = n; //直接通过下标访问修改
}void SListErase(SL* s, int pos)
{assert(s);assert(pos >= 0 && pos < s->size); //pos范围合法判断int cur = pos;while (cur < s->size){s->a[cur] = s->a[cur+1]; //挪动位置cur++;}s->size--;}void SListInsert(SL* s, int pos, SLDateType n)
{assert(s);assert(pos >= 0 && pos <= s->size); //判断pos合法int end = s->size;int begin = pos;while (begin < end){s->a[end] = s->a[end - 1]; //挪动数据end--;}s->a[pos] = n; //修改数据s->size++;
}void DestoryList(SL* s)
{assert(s);free(s->a); //释放动态开辟的空间s->a = NULL; //置空s->capacity = s->size = 0;
}
四.顺序表的性能分析
问题:
1. 中间/头部的插入删除,时间复杂度为O(N);
2. 增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗;
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间;
思考:如何解决以上问题呢?
下一章链表结构就可以解决这个问题;
相关文章:
数据结构:顺序表的奥秘
🎉个人名片: 🐼作者简介:一名乐于分享在学习道路上收获的大二在校生🐻❄个人主页🎉:GOTXX 🐼个人WeChat:ILXOXVJE🐼本文由GOTXX原创,首发CSDN&a…...
conda 设置国内源 windows+linux
默认的conda源连接不好,时好时坏,而且速度很慢,可以使用国内的源 如果没有安装conda,可以参考: miniconda安装:链接 anaconda安装winlinux:链接 windows使用命令提示符,linux使用…...
SQL中的不加锁查询 with(nolock)
WITH(NOLOCK) 是一种 SQL Server 中的表提示(table hint),可以用来告诉数据库引擎在查询数据时不要加锁,以避免因为锁等待导致查询性能下降。 当多个事务同时访问同一张表时,数据库引擎会对表进行锁定,以确…...
代码讲解:如何把3D数据转换成旋转的视频?
目录 3D数据集下载 读取binvox文件 使用matplotlib创建图 动画效果 完整代码 3D数据集下载 这里以shapenet数据集为例,可以访问外网的可以去直接申请下载;我也准备了一个备份在百度网盘的数据集,可以参考: ShapeNet简介和下…...
LVS集群 ----------------(直接路由 )DR模式部署 (二)
一、LVS集群的三种工作模式 lvs-nat:修改请求报文的目标IP,多目标IP的DNAT lvs-dr:操纵封装新的MAC地址(直接路由) lvs-tun:隧道模式 lvs-dr 是 LVS集群的 默认工作模式 NAT通过网络地址转换实现的虚拟服务器&…...
微软亚太区AI智能应用创新业务负责人许豪,将出席“ISIG-AIGC技术与应用发展峰会”
3月16日,第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导,企智未来科技(AIGC开放社区、RPA中国、LowCode低码时代)主办。大会旨在聚合每一位产业成员的力量,深入探索A…...
vim寄存器和宏
目录 1.寄存器1.1.寄存器相关命令 2.宏2.1.宏的录制和回放2.1.1.避免宏回放回到开头重做2.1.2.先搜索 2.2.宏的编辑2.2.1.特殊字符 3.递归的宏4.跨文件运行宏 1.寄存器 寄存器说明注释a-z手动复制数据"寄存器"无名寄存器""p等效为p0-9最后10次删除操作的历…...
使用数据库实现增删改查
#include<myhead.h>//定义添加数据函数int do_add(sqlite3 *ppDb) {//1.准备sql语句,输入要添加的信息int add_numb; //工号char add_name[20]; //姓名char add_sex[10]; //性别double add_score; //工资printf("请输入要添加的工号:")…...
Oracle Essbase 多维库导入文件数据步骤操作
第一步: 先确定导入数据的维度数量(清楚自己需要导入什么数据和范围) 第二步: 设置加载的规则 1.创建规则 2.编辑规则-》打开数据文件 通过数据文件来确定加载规则的加载格式 先查看数据文件格式: 将数据文件导入&…...
【自然语言处理】BitNet b1.58:1bit LLM时代
论文地址:https://arxiv.org/pdf/2402.17764.pdf 相关博客 【自然语言处理】【大模型】BitNet:用1-bit Transformer训练LLM 【自然语言处理】BitNet b1.58:1bit LLM时代 【自然语言处理】【长文本处理】RMT:能处理长度超过一百万t…...
【Axure高保真原型】可视化动点素材
今天和粉丝们免费分享可视化动点素材的原型模板,该模板使用简单,复制粘贴,预览时即可实现动点效果,本案例提供红黄蓝绿4中颜色的动点,如果需要其他颜色,可以自行编辑svg里面的代码 【原型效果】 【模板下载…...
分布式数据库 GaiaDB-X 金融应用实践
1 银行新一代核心系统建设背景及架构 在银行的 IT 建设历程中,尤其是中大行,大多都基于大型机和小型机来构建核心系统。随着银行业务的快速发展,这样的系统对业务的支持越来越举步维艰,主要体现在以下四个方面: 首先是…...
机器学习中的经典算法总结
经典算法 有监督算法逻辑回归支持向量机SVM决策树朴素贝叶斯K近邻(KNN) 无监督算法K-meansPCA主成分分析预留模版 有监督算法 逻辑回归 简介 逻辑回归是机器学习中一种经典的分类算法,通常用于二分类任务,基本思想是构建一个线性…...
ElasticSearch 学习(docker,传统方式安装、安装遇到的问题解决,)
目录 简介 什么是ElasticSearch 安装 传统方式安装 开启远程访问 Docker方式安装 Kibana 简介 安装 传统方式安装 Docker方式安装 compose方式安装 简介 什么是ElasticSearch ElasticSearch 简称 ES ,是基于Apache Lucene构建的开源搜索引擎,…...
[百度二面]操作系统进程、锁相关面试题
2.22 什么是死锁 在多道程序环境下,多个进程可以竞争有限数量的资源。当一个进程申请资源时,如果这时没有可用资源,那么这个进程进入等待状态。有时,如果所申请的资源被其他等待进程占有,那么该等待进程有可能再也无法…...
IP劫持的危害及应对策略
随着互联网的发展,网络安全问题日益凸显,其中IP劫持作为一种常见的网络攻击手段,对个人和企业的信息安全造成了严重的威胁。IP数据云将分析IP劫持的危害,并提出相应的应对策略。 IP地址查询:IP数据云 - 免费IP地址查询…...
Mac安装oh-my-zsh
目录 命令下载 卸载命令 注意 命令下载 curl -L https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | sh 卸载命令 uninstall_oh_my_zsh 注意 终端init的时候并不会执行~/.bash_profile、~/.bashrc等脚本了, 这是因为其默认启动执行脚本…...
【Web开发】深度学习HTML(超详细,一篇就够了)
💓 博客主页:从零开始的-CodeNinja之路 ⏩ 收录文章:【Web开发】深度学习html(超详细,一篇就够了) 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 HTML1. HTML基础1.1 什么是HTML1.2 认识HTML标签1.3 HTML文件基本…...
深入了解二叉搜索树:原理、实现与应用
目录 一、介绍二叉搜索树 二、二叉搜索树的基本性质 三、二叉搜索树的实现 四、总结 在计算机科学中,数据结构是构建算法和程序的基础。其中,二叉搜索树(Binary Search Tree,简称 BST)作为一种常见的数据结构&#…...
【MybatisPlus】BaseMapper详解,举例说明
一、BaseMapper 简介 MyBatis-Plus 的核心类 BaseMapper 主要是用于提供基本的 CRUD(创建、读取、更新、删除)操作的接口定义。它是 MyBatis-Plus 框架中的一个重要组成部分,可以大大简化基于 MyBatis 的数据访问层代码的编写。 BaseMapper…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
