当前位置: 首页 > news >正文

数据结构:顺序表的奥秘

🎉个人名片:

🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🐻‍❄个人主页🎉: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个数据空间;

思考:如何解决以上问题呢?

下一章链表结构就可以解决这个问题;




相关文章:

数据结构:顺序表的奥秘

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生&#x1f43b;‍❄个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE&#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&a…...

conda 设置国内源 windows+linux

默认的conda源连接不好&#xff0c;时好时坏&#xff0c;而且速度很慢&#xff0c;可以使用国内的源 如果没有安装conda&#xff0c;可以参考&#xff1a; miniconda安装&#xff1a;链接 anaconda安装winlinux&#xff1a;链接 windows使用命令提示符&#xff0c;linux使用…...

SQL中的不加锁查询 with(nolock)

WITH(NOLOCK) 是一种 SQL Server 中的表提示&#xff08;table hint&#xff09;&#xff0c;可以用来告诉数据库引擎在查询数据时不要加锁&#xff0c;以避免因为锁等待导致查询性能下降。 当多个事务同时访问同一张表时&#xff0c;数据库引擎会对表进行锁定&#xff0c;以确…...

代码讲解:如何把3D数据转换成旋转的视频?

目录 3D数据集下载 读取binvox文件 使用matplotlib创建图 动画效果 完整代码 3D数据集下载 这里以shapenet数据集为例&#xff0c;可以访问外网的可以去直接申请下载&#xff1b;我也准备了一个备份在百度网盘的数据集&#xff0c;可以参考&#xff1a; ShapeNet简介和下…...

LVS集群 ----------------(直接路由 )DR模式部署 (二)

一、LVS集群的三种工作模式 lvs-nat&#xff1a;修改请求报文的目标IP,多目标IP的DNAT lvs-dr&#xff1a;操纵封装新的MAC地址&#xff08;直接路由&#xff09; lvs-tun&#xff1a;隧道模式 lvs-dr 是 LVS集群的 默认工作模式 NAT通过网络地址转换实现的虚拟服务器&…...

微软亚太区AI智能应用创新业务负责人许豪,将出席“ISIG-AIGC技术与应用发展峰会”

3月16日&#xff0c;第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导&#xff0c;企智未来科技&#xff08;AIGC开放社区、RPA中国、LowCode低码时代&#xff09;主办。大会旨在聚合每一位产业成员的力量&#xff0c;深入探索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 多维库导入文件数据步骤操作

第一步&#xff1a; 先确定导入数据的维度数量&#xff08;清楚自己需要导入什么数据和范围&#xff09; 第二步&#xff1a; 设置加载的规则 1.创建规则 2.编辑规则-》打开数据文件 通过数据文件来确定加载规则的加载格式 先查看数据文件格式&#xff1a; 将数据文件导入&…...

【自然语言处理】BitNet b1.58:1bit LLM时代

论文地址&#xff1a;https://arxiv.org/pdf/2402.17764.pdf 相关博客 【自然语言处理】【大模型】BitNet&#xff1a;用1-bit Transformer训练LLM 【自然语言处理】BitNet b1.58&#xff1a;1bit LLM时代 【自然语言处理】【长文本处理】RMT&#xff1a;能处理长度超过一百万t…...

【Axure高保真原型】可视化动点素材

今天和粉丝们免费分享可视化动点素材的原型模板&#xff0c;该模板使用简单&#xff0c;复制粘贴&#xff0c;预览时即可实现动点效果&#xff0c;本案例提供红黄蓝绿4中颜色的动点&#xff0c;如果需要其他颜色&#xff0c;可以自行编辑svg里面的代码 【原型效果】 【模板下载…...

分布式数据库 GaiaDB-X 金融应用实践

1 银行新一代核心系统建设背景及架构 在银行的 IT 建设历程中&#xff0c;尤其是中大行&#xff0c;大多都基于大型机和小型机来构建核心系统。随着银行业务的快速发展&#xff0c;这样的系统对业务的支持越来越举步维艰&#xff0c;主要体现在以下四个方面&#xff1a; 首先是…...

机器学习中的经典算法总结

经典算法 有监督算法逻辑回归支持向量机SVM决策树朴素贝叶斯K近邻&#xff08;KNN&#xff09; 无监督算法K-meansPCA主成分分析预留模版 有监督算法 逻辑回归 简介 逻辑回归是机器学习中一种经典的分类算法&#xff0c;通常用于二分类任务&#xff0c;基本思想是构建一个线性…...

ElasticSearch 学习(docker,传统方式安装、安装遇到的问题解决,)

目录 简介 什么是ElasticSearch 安装 传统方式安装 开启远程访问 Docker方式安装 Kibana 简介 安装 传统方式安装 Docker方式安装 compose方式安装 简介 什么是ElasticSearch ElasticSearch 简称 ES &#xff0c;是基于Apache Lucene构建的开源搜索引擎&#xff0c…...

[百度二面]操作系统进程、锁相关面试题

2.22 什么是死锁 在多道程序环境下&#xff0c;多个进程可以竞争有限数量的资源。当一个进程申请资源时&#xff0c;如果这时没有可用资源&#xff0c;那么这个进程进入等待状态。有时&#xff0c;如果所申请的资源被其他等待进程占有&#xff0c;那么该等待进程有可能再也无法…...

IP劫持的危害及应对策略

随着互联网的发展&#xff0c;网络安全问题日益凸显&#xff0c;其中IP劫持作为一种常见的网络攻击手段&#xff0c;对个人和企业的信息安全造成了严重的威胁。IP数据云将分析IP劫持的危害&#xff0c;并提出相应的应对策略。 IP地址查询&#xff1a;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等脚本了&#xff0c; 这是因为其默认启动执行脚本…...

【Web开发】深度学习HTML(超详细,一篇就够了)

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【Web开发】深度学习html(超详细,一篇就够了) &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 HTML1. HTML基础1.1 什么是HTML1.2 认识HTML标签1.3 HTML文件基本…...

深入了解二叉搜索树:原理、实现与应用

目录 一、介绍二叉搜索树 二、二叉搜索树的基本性质 三、二叉搜索树的实现 四、总结 在计算机科学中&#xff0c;数据结构是构建算法和程序的基础。其中&#xff0c;二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称 BST&#xff09;作为一种常见的数据结构&#…...

【MybatisPlus】BaseMapper详解,举例说明

一、BaseMapper 简介 MyBatis-Plus 的核心类 BaseMapper 主要是用于提供基本的 CRUD&#xff08;创建、读取、更新、删除&#xff09;操作的接口定义。它是 MyBatis-Plus 框架中的一个重要组成部分&#xff0c;可以大大简化基于 MyBatis 的数据访问层代码的编写。 BaseMapper…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

云原生周刊:k0s 成为 CNCF 沙箱项目

开源项目推荐 HAMi HAMi&#xff08;原名 k8s‑vGPU‑scheduler&#xff09;是一款 CNCF Sandbox 级别的开源 K8s 中间件&#xff0c;通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度&#xff0c;为容器提供统一接口&#xff0c;实现细粒度资源配额…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...