顺序表:数据结构的建筑积木

news2024/9/24 9:21:00

朋友们大家好啊,本节内容我们进入数据结构的第二节,顺序表有关内容,同步我们会学习计组原理与cpp相关知识,求三连啊!

本节我们重点探讨动态顺序表关于插入数据和删除数据的多种情况的分析

顺序表

  • 线性表
  • 顺序表
    • 静态顺序表
  • 动态顺序表
    • 顺序表的初始化与销毁
    • 顺序表头部尾部的插入与删除
    • 指定位置插入和删除

线性表

线性表是数据结构的一种,它是一组具有相同数据类型的数据元素的有限序列。在线性表中,除了第一个和最后一个数据元素之外,每个数据元素均只有一个直接前驱和一个直接后继。线性表的元素个数n(n≥0)定义为线性表的长度,当n=0时,称为空表。

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储

线性表的物理存储结构影响其操作的效率,主要分为两种:

  1. 顺序存储结构:
  2. 链式存储结构:

我们接下来介绍顺序表有关内容

顺序表

介绍顺序表之前,我们谈论一下数组

数组是程序设计中的一种基本数据结构,它是同一数据类型元素的集合,这些元素在内存中按照顺序排列,占据连续的内存空间。数组是静态的数据结构,它的大小在定义时就已确定,并且在整个生命周期中保持不变。数组可以是一维的,也可以是多维的(如二维数组、三维数组等)。

特点:

  • 静态结构:一旦定义,大小不可变。
  • 连续的内存空间。
  • 支持随机访问,即可以通过索引访问任意元素。
  • 大小固定,一旦数组被声明,它的大小就被确定下来,不能动态地增加或减少元素。

那么对于顺序表,通常使用数组作为其底层的物理结构,但它是一个更高级别的抽象。与“裸”数组不同的是,顺序表通常提供了一组用于操作和访问其元素的API接口,如插入、删除、搜索等操作,并且它们的实现细节对使用者是隐藏的。在一些实现中,顺序表还可以动态地调整其大小以适应元素数量的变化,这是通过在后台自动重新分配内存和复制现有元素到一个更大(或更小)的数组来实现的。

数组有给定长度的,也有动态的,顺序表也分为静态和动态

静态顺序表

静态顺序表:使用定长数组存储元素

#define N 7
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType arr[N];
	size_t size;
}SeqList;

在这里,我们设置了一个定长数组arr,size为它的有效数据的个数,这里有效数据的个数是指已经初始化或赋值的部分,同时我们用新的类型别名 SLDataType 来代表 int 类型,这种操作再数据结构中非常常见,主要目的:

类型抽象:通过使用类型别名,可以将数据类型抽象化。这意味着如果将来需要改变数据类型(比如从 int 改为 float 或者某个结构体类型),只需修改 typedef 行的定义,而不用修改整个代码中的多个地方。这提高了代码的可维护性。我们展开讨论:

假设您在一个较大的项目中定义了一个数据类型别名 SLDataType 来代表 int,并在多个函数和数据结构中广泛使用了这个别名。现在,我们来看看如果需要更改这个数据类型,类型别名如何简化这个过程。

typedef int SLDataType; // 初始类型别名定义

// 使用SLDataType的函数
void processElement(SLDataType element) {
    // ... 处理逻辑 ...
}

// 使用SLDataType的数据结构
typedef struct {
    SLDataType array[10];
    int size;
} DataArray;

在这个初始代码中,SLDataType 被用于函数 processElement 和结构体 DataArray。

更改数据类型
现在,假设您决定将 SLDataType 从 int 更改为 float。这种情况下,您只需修改 typedef 行:

typedef float SLDataType; // 修改类型别名

由于 SLDataType 被用于整个项目中,这一改变会自动应用于所有使用了 SLDataType 的地方。这意味着您不需要逐个查找和替换每个 int 类型的实例。processElement 函数和 DataArray 结构体现在都会使用 float 而不是 int,而且不需要对它们的代码进行任何修改

动态顺序表

动态顺序表是线性表顺序存储方式的一种动态实现,它能够根据需要动态调整内存空间的大小,从而适应元素数量的变化

typedef struct SeqList
{
	SLDataType *array;
	size_t size;
	size_t capacity;
}SL;

这里size为有效数据的大小,capacity为空间容量,后续的增容与此变量息息相关

这里我们构建一个头文件(seq.h),包含所要调用所有顺序表函数的信息:

typedef struct SeqList
{
 SLDataType* a;
 int size; // 有效数据个数
 int capacity; // 空间容量
}SL;
//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);
//头部插⼊删除 / 尾部插⼊删除
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
//指定位置之前插⼊/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

接下来我们逐个讲解

顺序表的初始化与销毁

思考下面这种方式能不能进行初始化?

void SLInit(SL ps)

在这里插入图片描述
这串代码并不能改变原来所创建的ps,这里是传值调用,为了使这种修改有效,需要通过指针传递SL结构。这样,SLInit将获取一个指向SL结构实例的指针,使其能够修改原始实例的内容。

修改如下:

void SLInit(SL*ps)
{
    ps->array = NULL;
    ps->size = 0;
    ps->capacity = 0;
}

在这里插入图片描述
这里若ps为空指针,则可能发生未定义行为,我们在开始进行判断

void SLInit(SL* ps)
{
    if (ps == NULL) { // 检查 ps 是否为 NULL
        // 可以打印错误信息,直接返回或者采取其他措施
        fprintf(stderr, "Error: NULL pointer passed to SLInit.\n");
        return;
    }

    ps->array = NULL;
    ps->size = 0;
    ps->capacity = 0;
}

在头文件中我们进行声明,在SeqList.c中完成函数的功能,在test.c文件中进行测试代码。
在这里插入图片描述
销毁

void SLDestroy(SL* ps)
{
    if (ps->array != NULL)
    {
        free(ps->array);
        ps->array = NULL;
        ps->size = 0;
        ps->capacity = 0;
    }
}

在这里插入图片描述
free(ps->array);这行代码的作用是释放顺序表(SeqList)中动态分配的数组内存。当ps->array不为NULL时,表示array指向了一块之前分配的内存,使用free来释放这块内存

顺序表头部尾部的插入与删除

这里我们定义四组函数,分别表示顺序表尾部的插入与删除,头部的插入与删除

void SLPushBack(SL* ps, SLDataType x);//尾插
void SLPopBack(SL* ps);//尾删
void SLPushFront(SL* ps, SLDataType x);//头插
void SLPopFront(SL* ps);//头删

首先来讨论尾部插入,这里有几种情况,即尾部有没有空间插入
在这里插入图片描述
如果空间足够,直接在尾部放入数据即可。
比如插入数据“6”

ps->arr[ps->size++]=6;

如果size和capacity相等了,说明满了,如果再存储则会越界;这里就需要扩容

if (ps->size == ps->capacity)
{ 
    int newcapacity = ps->capacity == 0 ? 4 : ps->capacity;
    SLDataType* tmp = realloc(ps->array, sizeof(SLDataType) * newcapacity);
}

由于初始化的时候我们将capacity的值赋值为0,这里进行新的capacity扩容的时候就用三目运算符如果为0,赋予值为4,如果不为零,给其2倍扩容。

realloc进行扩容,判断是否开辟成功

 if (tmp==NULL)
 {
     perror("realloc fail");
     return;
 }

如果开辟成功,将新开辟的空间的地址给arr数组

ps->array = tmp;

完整的扩容代码如下:

 if (ps->size == ps->capacity)
 { 
     int newcapacity = ps->capacity == 0 ? 4 : ps->capacity;
     SLDataType* tmp = (SLDataType*) realloc(ps->array, sizeof(SLDataType) * newcapacity);
     if (tmp==NULL)
     {
         perror("realloc fail");
         return;
     }
     ps->array = tmp;
     ps->capacity = newcapacity;
 }

我们将这串代码放在SLCheckcapacity中
在这里插入图片描述

我们在测试文件中进行测试
在这里插入图片描述
调试如下
在这里插入图片描述
结果打印
在这里插入图片描述
接下来看头部插入
直接调用SLCheckcapacity检查空间是否足够

void SLPushFront(SL* ps, SLDataType x)
{
    SLCheckcapacity(ps);
}

头部插入,我们需要将数据往后挪动

void SLPushFront(SL* ps, SLDataType x)
{
    SLCheckcapacity(ps);
    int end =ps-> size;
    while (end >= 0)
    {
        ps->array[end + 1] = ps->array[end];
        end--;
    }
    ps->array[0] = x;
    ps->size++;
}

最后让size指向下一个位置
示例如下:
在这里插入图片描述

接下来我们讨论尾部删除

尾删如何删除呢?

这里我们需要讨论是否有数据去删除

代码如下:

void SLPopBack(SL* ps)
{
    if (ps->size == 0)
    {
        printf("The SeqList is empty, no elements to remove.\n");
    }
    else
    {
        ps->size--;
    }
}

顺序表的size属性标志着其中有效元素的数量。当我们进行size- -操作时,我们实际上是在逻辑上减少了顺序表中的元素数量,而不是在物理上从内存中移除该元素。被"删除"的元素在内存中依然存在,只是我们不再将其视为顺序表的一部分。

在多数情况下,顺序表的实现不会立即释放每次删除操作后的内存空间,因为频繁的内存分配和释放操作会影响性能。相反,它保留这些空间以支持未来的添加操作,从而提高了整体的内存使用和管理效率。

在这里插入图片描述

我们这里使用if语句可以避免size减为负值,避免后续插入时候缺少数据!!!

头部删除
头部删除,我们可以用数据往前挪动进行数据覆盖

void SLPopFront(SL* ps)
{
    if (ps->size == 0)
    {
        printf("The SeqList is empty, no elements to remove.\n");
        return;
    }

    for (size_t i = 1; i < ps->size; i++)
    {
        ps->array[i - 1] = ps->array[i];
    }

    ps->size--;
}

指定位置插入和删除

这里定义两个函数,删除或插入指定位置pos的数据

void SLinsert(SL* ps,int pos, SLDataType x);//顺序表在pos位置插入x
void SLErase(SL* ps, int pos);//顺序表删除pos位置的值

关于数据插入,首先判断三件事:

  1. ps是否为空指针
  2. pos是否在规定位置
  3. 空间是否足够
void SLinsert(SL* ps, int pos, SLDataType x)
{
    assert(ps);
    assert(pos >= 0 && pos < ps->size);
    SLCheckcapacity(ps);
}

接下来进行数据挪动

void SLInsert(SL* ps, int pos, SLDataType x)
{
    assert(ps != NULL);
    assert(pos >= 0 && pos <= ps->size); 

    SLCheckCapacity(ps);
    for (int i = ps->size; i > pos; --i)
    {
        ps->array[i] = ps->array[i - 1];
    }
    // 在pos位置插入新元素
    ps->array[pos] = x;
    
    ps->size++;
}

进行检查
在这里插入图片描述

这里进行思考,如果pos等于size是什么结果?

如果pos等于size,size是有效位置长度,在pos位置插入数据,则相当于尾插

指定位置删除
首先进行判断是否为空指针和指定位置,再进行删除,代码如下

void SLErase(SL* ps, int pos)
{
    assert(ps != NULL);
    assert(pos >= 0 && pos < ps->size); // 确保pos在有效范围内

    // 从pos位置开始,将后面的元素前移
    for (size_t i = pos; i < ps->size - 1; i++)
    {
        ps->array[i] = ps->array[i + 1];
    }

    // 更新顺序表的大小
    ps->size--;
}

这里pos就不能等于size!

本节内容到此结束!感谢观看!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1430510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浪漫的通讯录(顺序表篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人能…

[python] os.fork

文章目录 使用 os.fork()注意事项示例安全使用 os.fork()底层原理 os.fork() 是 Python 中用于 Unix/Linux 系统的一个函数&#xff0c;它在当前进程中创建一个子进程。这个函数是 os 模块的一部分&#xff0c;直接调用了 Unix/Linux 系统的 fork 系统调用。fork 系统调用非常基…

Wiringpi不支持树莓派5了, Wiringpi官方好像不更新了

买了树莓派5才知道&#xff0c;Wiringpi不支持树莓派5了&#xff0c; Wiringpi官方好像不更新了。那用什么来替代呢&#xff1f; 通过资料查询&#xff0c;libgpiod 支持io控制&#xff1b; https://github.com/brgl/libgpiod //gpio库 gpiodetect #检测支持的io 可以看到&a…

SpringBoot注解--05--注解@Valid

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1 前言1.1 Bean Validation1.2 Valid实际案例1.3 Spring 中的 valid 注解 2 Valid 详解2.1 源码解析2.2 参数校验使用注解2.3 具体使用流程POST 则可以以实体对象为…

再谈Redis三种集群模式:主从模式、哨兵模式和Cluster模式

总结经验 redis主从:可实现高并发(读),典型部署方案:一主二从 redis哨兵:可实现高可用,典型部署方案:一主二从三哨兵 redis集群:可同时支持高可用(读与写)、高并发,典型部署方案:三主三从 一、概述 Redis 支持三种集群模式,分别为主从模式、哨兵模式和Cluster模式。…

Java并发基础:CountDownLatch全面解析!

内容概要 CountDownLatch的优点在于能够简洁高效地协调多个线程的执行顺序&#xff0c;确保一组线程都完成后才触发其他线程的执行&#xff0c;适用于资源加载、任务初始化等场景。它提供了清晰的等待/通知机制&#xff0c;易于理解和使用&#xff0c;是提升多线程程序性能和可…

ChatGPT prompt概述

ChatGPT prompt概述 2022年11月30日&#xff0c;由人工智能实验室Open AI发布的对话式大型语言模型ChatGPT一夜爆火。凭借其强大的文字处理和人机交互能力迅速成为炙手可热的新一代人工智能产品。ChatGPT号称史上最强大的人工智能&#xff0c;它通过学习和理解人类语言与我们对…

玩具取名

看到长度是\(200\)&#xff0c;想到区间DP 但在这里说一下&#xff0c;设\(f[i][j]\)表示前\(i\)个字符&#xff0c;转换后以\(j\)结尾的最短长度是推不走的&#xff0c;因为原来的字符串的第\(i\)个字符合并之后产生的新字符有可能继续合并&#xff0c;这是有问题的

【成品论文57页】2024美赛F题成品论文57页+每一小问配套代码数据

基于数据预测下的减少非法野生动物贸易研究 近年来&#xff0c;非法野生动物贸易每年涉及的金额高达 265 亿美元&#xff0c;被认为是全球第四大 非法贸易。本文基于收集的数据&#xff0c; 对非法野生动物贸易进行研究。 问题一&#xff0c;为了确定五年项目的研究对象我们利用…

PXIe-5842第三代PXI矢量信号收发器简介

内容 简介​PXIe-5842 VST的主要特性PXI VST软件工具PXI VST应用结论下一步 简介 NI于2012年引入了矢量信号收发器(VST)的概念。VST将RF信号发生器、RF信号分析仪和功能强大的FPGA集成在单个PXI模块上。PXIe-5842 VST是首款提供30 MHz到26.5 GHz连续频率覆盖范围的VST。PXIe…

百分点科技:《数据科学技术: 文本分析和知识图谱》

科技进步带来的便利已经渗透到工作生活的方方面面&#xff0c;ChatGPT的出现更是掀起了新一波的智能化浪潮&#xff0c;推动更多智能应用的涌现。这背后离不开一个朴素的逻辑&#xff0c;即对数据的收集、治理、建模、分析和应用&#xff0c;这便是数据科学所重点研究的对象——…

Blender 与 3ds Max | 面对面的直接较量(2024)

Blender和3ds Max&#xff0c;哪个动画软件更好&#xff1f;作为一个从事动画领域十年的专业人士&#xff0c;Mark McPherson提供了八条最新建议&#xff0c;帮助你了解哪个软件更适合满足你的3D动画需求。 1.建模 获胜者&#xff1a;3ds Max。3ds Max的建模机制已经被证明是…

Leetcode刷题笔记题解(C++):36. 有效的数独

思路一&#xff1a;暴力破解&#xff0c;两个二维数组记录行、列对应的数字出现的次数&#xff0c;比如rows[i][index]表示的数字index在i行出现的次数&#xff0c;三维数组记录每个块中对应数字出现的次数&#xff0c;比如boxes[i/3][j/3][index]表示的数字index在[i/3][j/3]个…

031 递归

何为递归 示例 public static void main(String[] args) {System.out.println(fn(5)); }static int fn(int a){return a 1 ? 1 : a * fn(a - 1); }

conda虚拟环境基础

【一文搞定最新版Anaconda】Win11 安装 Anaconda&#xff08;2023.9&#xff09;详解&#xff08;不删除旧版情况下下载、安装、注册、登录、设置环境变量、迁移旧环境、配置修改换源等&#xff09;连接Pycharm_win11安装anaconda-CSDN博客 conda命令大全&#xff08;create/in…

基于大数据的淘宝电子产品数据分析的设计与实现

&#xff08;1&#xff09;本次针对开发设计系统并设置了相关的实施方案&#xff0c;利用完整的软件开发流程进行分析&#xff0c;完成了设置不同用户的操作权限和相关功能模块的开发&#xff0c;最后对系统进行测试。 &#xff08;2&#xff09;框架可以帮助程序开发者快速构建…

【Java程序设计】【C00195】基于SSM的影视创作论坛管理系统(论文+PPT)

基于SSM的影视创作论坛管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的影视创作论坛 本系统分为前台系统、后台管理员和后台会员3个功能模块。 前台系统&#xff1a;当游客打开系统的网址后&#xff0c;首先看…

2024美赛B题Searching for Submersibles原创论文完整版

Searching for Submersibles搜索潜水器 2024美赛B题Searching for Submersibles原创论文&#xff08;共38页&#xff09;部分内容&#xff0c;其余见文末&#xff1a; 整体框架&#xff1a; 1.1 问题背景与问题重述 海上游轮迷你潜水艇公司&#xff08;MCMS&#xff09;&…

前端学习笔记 | HTML5+CSS3静态网页制作的技巧(持续更新)

注&#xff1a;本文的css样式均使用less写法 1、字体居中 &#xff08;1&#xff09;先text-align:center;行内元素水平居中 &#xff08;2&#xff09;再line-heigh:(盒子高度);行内元素垂直居中 text-align: center;line-height: ( 30 / vw ); 2、盒子居中 情景1&#…

Vue引入Axios

1.命令安装axios和vue-axios npm install axios --save npm install vue-axios --save 2.package.json查看版本 3.在main.js中引用 import axios from axios; import VueAxios from vue-axios; Vue.use(VueAxios,axios) 4.如何使用 &#xff08;初始化方法&#xff09; 将下列代…