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

顺序表(超详解哦)

全文目录

  • 引言
  • 顺序表定义
    • 静态顺序表
    • 动态顺序表
  • 动态顺序表的接口实现
    • 顺序表的初始化与销毁
    • 顺序表尾插/尾删
    • 顺序表头插/头删
    • 顺序表在pos位置插入/删除
    • 顺序表的打印
    • 顺序表中的查找
  • 总结

引言

在生产中,为了方便管理数据,我们经常会需要将一些数据连续的存储起来。例如手机的通讯录中需要存储联系人的信息;图书管理系统中需要存储图书的信息等。

想到存储一系列相同类型的数据,我们就不免想到数组。数组可以实现将一些相同类型的数据存储到一块连续的空间中。其实,我们在这篇文章中要介绍的顺序表中的数据就是以数组的形式存储的。

顺序表定义

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

为了方便管理数据,我们通常会将存储数据的数组与目前数据的状态(顺序表中已经存储元素的个数等)放在一个结构体变量中。

静态顺序表

静态顺序表就是使用定长的数组存储数据的顺序表。

我们需要将存储数据的数组与当前已存储的数据的个数放在一个结构体变量中,以方便对数据进行管理:

typedef int SLDateType;typedef struct SeqList
{SLDateType arr[10];size_t size;
}SeqList;

但是,这样存储数据是有很明显的缺陷的:就是空间的大小一旦确定下来就不能改变了,当数据存储满之后也不能实现扩容。

所以,我们可以使用动态顺序表来实现:

动态顺序表

动态顺序表就是使用动态开辟的数组存储数据的顺序表:

我们需要将存储数据的动态空间的地址、当前已经存储的数据的个数与顺序表的容量大小放在一个结构体变量中,方便对数据进行管理:

typedef int SLDateType;typedef struct SeqList
{SLDateType* arr;size_t size;size_t capacity;
}SeqList;

在这里插入图片描述

SLDateType* arr指向的空间是动态开辟的,当需要扩容时,只需要使用realloc函数进行扩容即可。

动态顺序表的接口实现

在有了顺序表的相关概念后,我们就可以尝试实现一下顺序表
静态顺序表的实现其实是较为简单的,这里就只介绍动态顺序表的实现:

首先,我们需要将上述的SeqList类型的结构体定义出来。但此时它的成员为一个SLDateType*型的指针、任意值的size变量与capacity变量。并没有任何意义,所以,我们需要对这个结构体中的成员进行初始化:

顺序表的初始化与销毁

初始化函数:void SeqListInit(SeqList* ps);

对于初始化函数,只有一个参数就是我们创建的结构体的结构体指针。在这个函数中,我们需要实现动态开辟一块空间用来存放数据,并且将size与capacity的值初始化为0:

void SeqListInit(SeqList* ps)
{assert(ps);ps->arr = (SLDateType*)calloc(INIT, sizeof(SLDateType));if (ps->arr == NULL){perror(calloc);return;}ps->capacity = INIT;ps->size = 0;
}

我们的空间是动态开辟的,在使用结束后自然需要free释放

内存释放函数:void SeqListDestroy(SeqList* ps)

void SeqListDestroy(SeqList* ps)
{assert(ps);free(ps->arr);ps->arr = NULL;ps->capacity = 0;ps->size = 0;
}

有了存储数据的空间,我们就需要实现对这些数据的操作:无非增、删、查、改。
我们将逐一实现这些操作:

顺序表尾插/尾删

顺序表的尾插就是在顺序表的末尾插入一个值。
我们直接在顺序表中下标为size(结构体中的成员)的位置插入一个数据即可。

但是,这样的想法是有漏洞的,当size等于capacity时,即顺序表已经存满的时候。我们如果还将数据存在下标为size的位置,就会出现数组越界的问题。所以插入数据前,我们需要判断是否需要扩容,如果需要,则使用realloc扩容后再插入数据:
(别忘了插入后size++)

void SeqListPushBack(SeqList* ps, SLDateType x)
{assert(ps);if (ps->capacity == ps->size){SLDateType* ptr = (SLDateType*)realloc(ps->arr, 2 * ps->capacity * sizeof(SLDateType));if (ptr == NULL){perror("realloc");return;}ps->arr = ptr;ps->capacity *= 2;}*(ps->arr + ps->size++) = x; 
}

顺序表的尾删就是删除顺序表中的最后一个数据:

当然,当顺序表中的数据数(size)为0时,就不执行此函数。这里我们可以直接使用assert来判断:
(别忘了删除后size–)

void SeqListPopBack(SeqList* ps)
{assert(ps);assert(ps->size > 0);*(ps->arr + --(ps->size)) = 0;
}

顺序表头插/头删

顺序表的头插就是在顺序表的前面插入一个数据。

此时,我们显然是不能直接用数据覆盖第一个数据的。而是需要将顺序表中的数据整体向后移动一个元素的位置,然后再将第一个元素的位置覆盖。
当然,头插也需要判断顺序表是否已满:
(别忘了插入后size++)

void SeqListPushFront(SeqList* ps, SLDateType x)
{assert(ps);if (ps->capacity == ps->size){SLDateType* ptr = (SLDateType*)realloc(ps->arr, 2 * ps->capacity * sizeof(SLDateType));if (ptr == NULL){perror("realloc");return;}ps->arr = ptr;ps->capacity *= 2;}for(size_t i = ps->size; i > 0; i--){*(ps->arr + i) = *(ps->arr + i - 1);}*ps->arr = x;ps->size++;
}

顺序表的头删就是将顺序表中最前面的元素删除。
首先判断size是否为0。然后我们可以直接用后面的元素覆盖前面一个的元素,这样可以直接实现删除第一个元素:
(别忘了删除后size–)

void SeqListPopFront(SeqList* ps)
{assert(ps);assert(ps->size > 0);for (size_t i = 1; i < ps->size; i++){*(ps->arr + i - 1) = *(ps->arr + i);}ps->size--;
}

顺序表在pos位置插入/删除

实现了头插头删、尾插尾删后,我们再进一步思考,能不能实现在顺序表的任意位置插入或删除任意位置的元素:

在pos位置插入数据时:
同样需要判断是否已满。我们需要将从pos开始的元素向后移动,然后再将元素插入到pos位置即可:
(别忘了插入后size++)

void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{assert(ps);if (ps->capacity == ps->size){SLDateType* ptr = (SLDateType*)realloc(ps->arr, 2 * ps->capacity * sizeof(SLDateType));if (ptr == NULL){perror("realloc");return;}ps->arr = ptr;ps->capacity *= 2;}for (int i = ps->size; i > pos; i--){*(ps->arr + i) = *(ps->arr + i - 1);}ps->size++;*(ps->arr + pos) = x;
}

删除pos位置的元素时,首先判断size是否为0。然后只需要将从pos后的元素统一向前覆盖即可实现pos位置数据的删除:
(别忘了删除后size–)

void SeqListErase(SeqList* ps, int pos)
{assert(ps);assert(ps->size > 0);for (size_t i = pos; i < ps->size - 1; i++){*(ps->arr + i) = *(ps->arr + i + 1);}*(ps->arr + --(ps->size)) = 0;
}

顺序表的打印

打印顺序表中元素时,直接便利顺序表打印即可:

void SeqListPrint(SeqList* ps)
{assert(ps);for (size_t i = 0; i < ps->size; i++){printf("%d ", *(ps->arr + i));}
}

顺序表中的查找

查找顺序表中数据时,只需要将顺序表中度元素遍历,逐个与输入元素比较即可。查找到后,返回下标,否则返回0:

int SeqListFind(SeqList* ps, SLDateType x)
{assert(ps);for (size_t i = 0; i < ps->size; i++){if (*(ps->arr + i) == x){return i + 1;}}return -1;
}

总结

到此,关于顺序表的所有内容就介绍完了。不难发现,这些数据存储的形式可以抽象化为线性,顺序表其实就是线性表的一种。

线性表是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
用的数据结构,常见的线性表有顺序表、链表、栈、队列、字符串等。

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。在下一篇文章我们将要介绍的链表也是线性表的一种。

如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出

如果本文对你有帮助,希望一键三连哦

希望与大家共同进步哦

相关文章:

顺序表(超详解哦)

全文目录引言顺序表定义静态顺序表动态顺序表动态顺序表的接口实现顺序表的初始化与销毁顺序表尾插/尾删顺序表头插/头删顺序表在pos位置插入/删除顺序表的打印顺序表中的查找总结引言 在生产中&#xff0c;为了方便管理数据&#xff0c;我们经常会需要将一些数据连续的存储起…...

Compose-Animation高级别动画

目录前言AnimatedVisibilityisScrollingUpFABscaffoldanimateContentSizeCrossfade顶部气泡下弹前言 AnimatedVisibility 驱动可视性相关动画&#xff0c;即布局显隐 animateContentSize 内容变换动画相关 Crossfade 布局&#xff08;或者页面&#xff09;切换过渡动画 Animat…...

c++11 标准模板(STL)(std::unordered_set)(八)

定义于头文件 <unordered_set> template< class Key, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator<Key> > class unordered_set;(1)(C11 起)namespace pmr { templ…...

Python每日一练(20230225)

目录 1. 整数反转 2. 求最大公约数和最小公倍数 最大公约数 最小公倍数 3. 单词搜索 II 附录&#xff1a; DFS 深度优先搜索算法 BFS 广度优先搜索算法 BFS 和 DFS 的区别 1. 整数反转 给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。…...

基于博客系统的测试用例

登陆界面博客预览页博客详情页博客编辑页...

C语言运算符算术运算符关系运算符

C 运算符 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 语言内置了丰富的运算符&#xff0c;并提供了以下类型的运算符&#xff1a; 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 杂项运算符 本章将逐一介绍算术运算符、关系运算符、逻辑运算符、位运…...

C语言 深度剖析数据在内存中的存储

目录数据类型详细介绍整形在内存中的存储&#xff1a;原码&#xff0c;反码&#xff0c;补码大小端字节序介绍及判断浮点型在内存中的存储解析数据类型详细介绍整形&#xff1a;1.为什么char类型也会归类到整形家族当中去呢&#xff1f;字符存储和表示的时候本质上使用的是ASCI…...

MyBatis快速开发

查询user表中的所有数据 步骤&#xff1a; 创建user表 打开Navicat&#xff0c;新建查询&#xff0c;将下面SQL代码复制粘贴并执行&#xff1a; create database mybatis; use mybatis;drop table if exists tb_user;create table tb_user(id int primary key auto_incremen…...

大数据常见应用场景及架构改进

大数据常见应用场景及架构改进大数据典型的离线处理场景1.大数据数据仓库及它的架构改进2.海量数据规模下的搜索与检索3.新兴的图计算领域4.海量数据挖掘潜在价值大数据实时处理场景大数据典型的离线处理场景 1.大数据数据仓库及它的架构改进 对于离线场景&#xff0c;最典型…...

【华为OD机试模拟题】用 C++ 实现 - 挑选字符串(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 货币单位换算(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 选座位(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 停车场最大距离(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 重组字符串(2023.Q1) 【华为OD机试模…...

程序员是世界上最理性、最睿智的群体,耶稣也反驳不了我,我说的!

有人说&#xff0c;程序员是吃青春饭的&#xff0c;35 岁就提前退休了。 猛一看&#xff0c;这句话是对的&#xff1b;仔细一看&#xff0c;这句话是不对的。 说它对&#xff0c;是因为现实中确实有很多程序员 35 岁就被毕业了&#xff1b;说它不对&#xff0c;是因为 35 岁以…...

人工智能到底是什么?

人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;是一种利用计算机科学和统计学理论和技术来实现人类智能的一门交叉学科&#xff0c;旨在使计算机系统能够模拟、扩展和增强人类的智能能力&#xff0c;使计算机能够像人类一样思考、学习、决策和执行任务…...

在动态规划的海洋中遨游(三)

前言&#xff1a;\textcolor{Green}{前言&#xff1a;}前言&#xff1a; &#x1f49e; 好久没写题&#xff0c;有点生疏了。这也是给大家提一个醒&#xff0c;一定要一直坚持下去&#xff0c;哪怕每天只做一点点。&#x1f49e; 算法类别一、算法介绍原理适用的情况做题步骤二…...

enable_if模板编程实现字节序转换模板

enable_if和SFINAESFINAE是模板的一个特性&#xff0c;也就是替换失败不报错。正常来说&#xff0c;函数匹配的时候按照优先级依次匹配定义的重载函数&#xff0c;最终选择最佳匹配的函数运行。模板也是一样的&#xff0c;但是在替换模板时&#xff0c;即使出现异常错误也不认为…...

【人工智能与深度学习】基于能量的模型

【人工智能与深度学习】基于能量的模型 概述能量基础模型(EBM)方法定义解决方案:基于梯度的推理有潜在变量的能量基础模型推理例子能量基础模型和机率模型的对比自由能(Free Energy)概述 我们现在介绍一个新框架来定义模型。它提供了一个统一和系列性的方式来定义「监督模型」…...

功能测试三年,是应该改变了

前言 测试行业3年多经验&#xff0c;学历大专自考本科&#xff0c;主要测试方向web&#xff0c;PC端&#xff0c;wap站&#xff0c;小程序公众号都测试过&#xff0c;app也测过一些&#xff0c;C端B端都有&#xff0c;除功能外&#xff0c;接口性能也有涉猎&#xff0c;但是不…...

基于STM32的ubuntu交叉编译环境的搭建(arm-gcc 8.2)

常用的STM32的软件开发方法都是基于MDK keil或IAR集成开发环境&#xff0c;但以上两个集成开发环境软件都是需要收费的&#xff0c;且价格较为昂贵。本节介绍一种在ubuntu上安装arm gcc&#xff08;arm-eabi&#xff09;的方式&#xff0c;用于编译STM32的程序。 1.在arm官网下…...

数据结构:二叉树概念篇(算法基础)

目录 一.有向树的图论基础 1.有向树的相关基本概念 有向树的基本定义: 有向树的结点的度&#xff1a; 有向树的度: 有向树的根结点,分枝结点,叶结点: 树的子树: 树结点的层次: 树的高度: 2.一个基本的数学结论 3.有序有向树 二.数据结构中树的顺序存储结构与链式存…...

华为OD机试真题Java实现【字符串变换最小字符串】真题+解题思路+代码(20222

字符串变换最小字符串 给定一个字符串s,最多只能进行一次变换,返回变换后能得到的最小字符串(按照字典序进行比较)。 变换规则:交换字符串中任意两个不同位置的字符。 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Java)真题目录汇总 ## 输入输出描述: …...

数字化转型的企业会用低代码平台深化重塑什么形态

随着数字化转型的浪潮不断推进&#xff0c;越来越多的企业开始关注如何更好地利用数字技术提高业务效率和创新能力。而低代码平台作为一种能够快速构建和部署应用程序的新型工具&#xff0c;正越来越受到企业的青睐。那么&#xff0c;数字化转型的企业会用低代码平台深化重塑什…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...

Linux中INADDR_ANY详解

在Linux网络编程中&#xff0c;INADDR_ANY 是一个特殊的IPv4地址常量&#xff08;定义在 <netinet/in.h> 头文件中&#xff09;&#xff0c;用于表示绑定到所有可用网络接口的地址。它是服务器程序中的常见用法&#xff0c;允许套接字监听所有本地IP地址上的连接请求。 关…...