数据结构之顺序表的增删查改

news2024/11/20 18:38:27

别丢了你的勇敢

前言:

自今日起,我们正式越过C语言的大山,走向了数据结构的深山,现如今摆在我们面前的第一个坎就是顺序表,我们需要了解顺序表的定义,并且知道,如何对其进行增删查改,之后我们需要在此处基础上写出一份通讯录代码,ok,顺序表,启动!

1.什么是顺序表

1.1线性表

线性表( linear list )是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中⼴泛使
⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。
线性表指的是具有部分相同特性的⼀类数据结构的集合

1.2顺序表

顺序表是一种线性表的数据结构,它是由一组具有相同特性的数据元素按照一定的顺序排列而成的。顺序表的底层结构是数组,对数组的封装,实现了常⽤的增删改查等接口。 顺序表可以使用数组来实现,也可以使用动态数组来实现。

顺序表分为静态顺序表和动态顺序表

静态顺序表是使用固定长度的数组来存储元素,数组的长度在创建时就确定了,无法改变。静态顺序表的优点是访问元素的时间复杂度为O(1),缺点是插入和删除元素的时间复杂度较高。

图片来自比特就业课官网链接:https://www.bitejiuyeke.com

动态顺序表是使用可以动态开辟的数组来存储元素,数组的长度可以根据需要进行动态调整。动态顺序表的优点是可以灵活地插入和删除元素,缺点是访问元素的时间复杂度为O(1)。

顺序表是一种常见的数据结构,它在实际中被广泛使用,常见的应用场景包括数组、字符串等。

图片来自比特就业课官网链接:https://www.bitejiuyeke.com

动态顺序表和静态顺序表的使用是极其相似的,只是静态的顺序表建立在栈区,动态顺序表通过动态内存分配建立于堆区,由于动态涉及了动态内存分配,难度会稍稍高一些,所以我们今天的增删查改直接是以动态顺序表为对象,如果你能明白了这个,那静态顺序表也是同样的原理,也是可以写出来的。

2、 动态顺序表的实现

2.1头文件

⭐️ 🌟我先把头文件列出来,让各位先知道我们要实现的内容有什么
# define INIT_CAPACITY 4
typedef int SLDataType;
// 动态顺序表 -- 按需申请
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 SLDelete(SL* ps, int pos);
// 指定位置修改 数据
void SLModify(SL* ps, int pos,SLDataType x);
// 指定位置查找 数据
void SLSearch(SL* ps, int pos, SLDataType x);

2.2具体分析

ok,然后咱们,从上到下,挨个分析

🍎2.2.1

#define INIT_CAPACITY 4

这是一个宏定义,也是我们初始化默认通讯录的初始容量,即四个单位空间

🍏2.2.2

typedef int SLDataType;

这是用typedef给int换了个名字,这时候肯定有人会问了,为啥不直接用int,

⭐️ 原因如下:

我们的顺序表是对数组的封装,但我们不能确实是什么类型的数组,如果我直接用int,那后面代码里也都是int,可假如我后来想给这个数组换成char类型呢,那我就要把所有int都改为char,于是乎我们直接用typedef创建一个类型名,之后代码也都用这个类型名,这样我之后想修改就只需要把

typedef int  SLDataType改为typedef char  SLDataType就ok了

这点在我们之后写通讯录时会体现出来

🍐 2.2.3

typedef struct SeqList
{
SLDataType* a;
int size; // 有效数据个数
int capacity; // 空间容量
}SL;
这是一个结构体,SLDataType*是顺序表中存储的元素类型,size是当前顺序表的存储数据数量,
capacity是顺序表的存储数据数量最大值。

🍊 2.2.4

void SLInit (SL* ps);
这是对顺序表的初始化,我们传一个顺序表变量进去,该函数对其进行初始化,具体如下
给ps->a开辟了4个单位空间
将通讯录目前数据数量设置为0
容量设置为4
void SLInit(SL* ps)
{
        ps->a = (SLDataType*)malloc(CAPACITY * sizeof(SLDataType));
        ps->size = 0;
        ps->capacity = 4;
}

🍋2.2.5

void SLDestroy (SL* ps);
有初始化就有销毁,当我们要退出程序时要对顺序表的内容进行销毁,这时候有人要问了:程序退出不是会自动销毁吗,为什么还要再写一个函数呢?
 ✨答:我们使用了动态内存开辟,有开辟就要有释放,当你不用它时就释放它是一个好的代码习惯,不然如果一直想着靠结束代码时释放空间以后当你写项目时就容易忘记及时释放空间导致内存泄漏。
 ✨具体如下:
把之前的空间释放掉
把通讯录目前的数据数量设置为0
把通讯录容量设置为0
void SLDestroy(SL* ps)
{
    free(ps->a);
    ps->a = NULL;
    ps->size = 0;
    ps->capacity = 0;

🍌 2.2.6

void SLPrint (SL* ps);
这个是打印顺序表的信息,直接遍历数组挨个打印就可以
循环控制条件依靠顺序表中的ps->size就可以
void SLPrint(SL* ps)
{
    for (int i = 0; i < ps->size; i++)
        printf("%d  ", ps->a[i]);
}

🍉 2.2.7

void SLCheckCapacity (SL* ps);
要知道我们给顺序表设置的初始容量只有4个单位,在你不断输入数据的情况下,他很快就会满,于是我们就需要设置一个函数用来给顺序表扩容
直接调用realloc函数就可以
这里我们的扩容方式是直接将容量扩大到现在容量的2倍
🔥🔥🔥 为什么不是扩大一个固定的数呢?🔥🔥🔥
假如我们每次扩2个或3个,那很容易就会不够,扩容很频繁,导致性能消耗,如果一次扩1000个,2000个又很容易空间浪费,但如果我们以倍数扩容,随着空间越来越大每次增加的空间也会越来越大,这样扩容就不会很频繁,浪费空间也不会很多,我们通常是采用2倍扩容或1.5倍扩容,至于为什么是这俩数字就涉及到数学原理了,我能力有限,无法作答。(去找你数分的朋友吧)
void SLCheckCapacity(SL* ps)
{
    SLDataType* p = (SLDataType*)realloc(ps->a, 2 * ps->capacity * sizeof(SLDataType));
    if (p == NULL)
    {
        perror("realloc fail");
        exit(1);
    }
    ps->a = p;
    ps->capacity *= 2;
}
🔥这里有个小知识点别忘了,realloc会自动释放之前的空间,所以不用free了

🍇 2.2.8

void SLPushBack(SL* ps, SLDataType x);  

☄️这个是尾插

  1. 在增加之前判断一下顺序表是不是满了,如果满了就调用扩容函数
  2. 再来一个尾插,也就是在数组最后面加入元素
  3. 之后直接在末尾加上该元素即可
void SLPushBack(SL* ps, SLDataType x)
{
    if (ps->size + 1 > ps->capacity)
        SLCheckCapacity(ps);
    ps->a[ps->size] = x;
    (ps->size)++;
}

🍓  2.2.9

void SLPopBack (SL* ps);
 ☄️ 这个是尾删
  1. 尾删之前要判断一下顺序表是不是空的,
  2. 如果是就打印提示信息,若不是就把最后一个元素设置其值为0,
  3. 然后把顺序表的当前数据数量减一
void SLPopBack(SL* ps)
{
    if (ps->size - 1 < 0)
    {
        printf("顺序表空了,无法删除\n");
        //perror("SLPopFront Fail");
        return ;
    }
    ps->a[ps->size - 1]=0;
    (ps->size)--;
}

🍈2.2.10

void SLPushFront (SL* ps, SLDataType x);
 ☄️这个是头插,比尾插麻烦一些,
  1. 第一步还是检验顺序表是不是满了
  2. 第二步我们要通过循环把所有元素集体向后移动一个单位,然后在空出来的第一个位置插入我们要插的值。
  3. 记得ps->size++
void SLPushFront(SL* ps, SLDataType a)
{
    if (ps->size + 1 > ps->capacity)
        SLCheckCapacity(ps);
    for (int i = 1; i <= ps->size; i++)
    {
        ps->a[i] = ps->a[i - 1];
    }
    (ps->size)++;
    ps->a[0] = a;
}

🍒 2.2.11

void SLPopFront (SL* ps);
 ☄️ 这个是头删
  1. 第一步检验顺序表是不是为空
  2. 第二步通过循环把元素集体向前移动一个单位,从而覆盖掉第一个元素
  3. 第三步ps->size--
void SLPopFront(SL* ps)
{
    if (ps->size - 1 < 0)
        perror("SLPopFront Fail");
    for (int i = 0; i < ps->size - 1; i++)
    {
        ps->a[i] = ps->a[i + 1];
    }
    ps->a[ps->size - 1] = 0;
    (ps->size)--;
}

🍑2.2.12

void SLInsert (SL* ps, int pos, SLDataType x);
 ☄️ 指定位置之前插⼊数据
  1. 第一步检查是否需要扩容
  2. 第二步通过循环让下标pos及pos之后的元素集体后移一个单位,
  3. 第三步把数据放入下标为pos的地方
void SLInsert(SL* ps, int pos, SLDataType x)
{
    if (ps->size + 1 < ps->capacity)
        SLCheckCapacity(ps);
    for (int i = ps->size; i > pos; i--)
        ps->a[i] = ps->a[i - 1];
    ps->a[pos] = x;
ps->size++;
}

🥭2.2.13

void SLDelete(SL* ps, int pos);
 ☄️ 指定位置删除数据
  1. 第一步检查顺序表是否为空
  2. 第二步通过循环把下标pos之后的元素向前移动一个单位,从而覆盖掉pos对位空间的值
  3. 第三步ps->size--
void SLDelete(SL* ps, int pos)
{
    if (ps->size - 1 < 0)
    {
        printf("顺序表空了\n");
        //perror("SLPopFront Fail");
        return;
    }
    for (int i = pos; i < ps->size - 1; i++)
        ps->a[i] = ps->a[i + 1];
    ps->size--;
}

🍍 2.2.14

void SLModify(SL* ps, int pos,SLDataType x);
 ☄️这个是修改数据:
先判断下标是否有效
若有效则修改数据
void SLModify(SL* ps, int pos,SLDataType x)
{
    if (pos >= ps->size)
        printf("要修改的元素不存在\n");
    else
        ps->a[pos] = x;
}

🍍 2.2.15

void SLSearch(SL* ps, int pos, SLDataType x);
☄️查找数据:
先判断下标是否有效
若有效则打印数据
{
    if (pos >= ps->size)
        printf("要查找的元素不存在\n");
    else
        printf("%d\n",ps->a[pos]);
}
ok,至此,我们知道了什么是顺序表,顺序表的增删查改四种功能我们也都实现了,可以说是迈出了相当大的一步,下一次我们将会在此基础上实现通讯录,
我先把要求放下面了,感兴趣的朋友可以自己动手试试哦
. 基于动态顺序表实现通讯录
C语⾔基础要求:结构体、动态内存管理、顺序表、⽂件操作
1、功能要求
1)⾄少能够存储100个⼈的通讯信息
2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等
3)增加联系⼈信息
4)删除指定联系⼈
5)查找制定联系⼈
6)修改指定联系⼈
7)显⽰联系⼈信息
当然了,与这次的顺序表不同的是我们下次还会用到文件操作来保存你存入的数据,毕竟写完就丢也太离谱了。
ok,那么今天在数据结构的第一场战役就打完了,倘若你觉得我的博客对你有帮助,就请点个免费的赞支持一下吧。

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

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

相关文章

欧科云链与《警察技术》联合发布技术专题.pdf

欧科云链受《警察技术》邀请&#xff0c;于第201期期刊正式刊登“区块链生态安全与虚拟货币犯罪治理”技术专题。欧科云链作为该技术专题主要作者&#xff0c;直接参与本次期刊2篇文章撰写&#xff0c;同时为多篇文章提供欧科云链的最新数据和研究成果。 《警察技术》期刊创办于…

HuoCMS|免费开源可商用CMS建站系统HuoCMS 2.0下载(thinkphp内核)

HuoCMS是一套基于ThinkPhp6.0Vue 开发的一套HuoCMS建站系统。 HuoCMS是一套内容管理系统同时也是一套企业官网建设系统&#xff0c;能够帮过用户快速搭建自己的网站。可以满足企业站&#xff0c;外贸站&#xff0c;个人博客等一系列的建站需求。HuoCMS的优势: 可以使用统一后台…

x-cmd pkg | yq - 命令行 YAML处理工具

目录 简介首次用户支持格式转换友好的显示和操作语法与 jq 类似竞品和相关作品进一步阅读 简介 yq (YAML Query) 是一个轻量级的 YAML、JSON、XML 处理器&#xff0c;主要用于查询和提取 YAML 数据。 本 yq 的包来自 mikefarah/yq 项目&#xff0c;语法类似于 jq 。相比 kisly…

【Python】使用Anaconda创建PyTorch深度学习虚拟环境

使用Anaconda Prompt 查看环境: conda env list 创建虚拟环境&#xff08;python3.10&#xff09;&#xff1a; conda create -n pytorch python3.10 激活创建的环境&#xff1a; conda activate pytorch在虚拟环境内安装PyTorch&#xff1a; 【Python】CUDA11.7/11.8安…

LMDeploy 大模型量化部署实践

文章目录 核心功能量化推理引擎推理服务 量化原理补充 部署&#xff1a; 在设备上运行起来&#xff0c;能够接受输入&#xff0c;返回输出。 最重要的就是性能和效率方面的考虑。大模型也是模型的一种&#xff0c;内存开销大&#xff0c;7b 要14G左右的显存。 因为是自回归的方…

虚拟机设置固定IP地址以及访问外网

一、虚拟机固定IP地址设置 1、IP地址查看命令 &#xff08;1&#xff09;ip a [rootlocalhost ~]# ip a • inet 192.168.93.129/24这表示该网络接口&#xff08;ens33&#xff09;被分配了一个IPv4地址是192.168.93.129&#xff0c;并且其子网掩码为 24位&#xff08;即/24…

python if条件判断的基础及应用

当前版本&#xff1a; Python 3.8.4 简介 if 语句是一种用于根据一个或多个条件的结果来执行不同代码块的控制流结构&#xff0c;它会检查给定的条件是否为真。如果条件为真&#xff0c;则执行与之关联的代码块&#xff1b;如果条件为假&#xff0c;则执行与之关联的其他代码块…

【 CSS 】基础 2

“生活就像骑自行车&#xff0c;想要保持平衡&#xff0c;就得不断前行。” - 阿尔伯特爱因斯坦 CSS 基础 2 1. emmet 语法 1.1 简介 Emmet语法的前身是 Zen coding&#xff0c;它使用缩写&#xff0c;来提高 HTML / CSS 的编写速度&#xff0c; VSCode 内部已经集成该语法。…

《剑指 Offer》专项突破版 - 面试题 21 : 删除倒数第 n 个节点(C++ 实现)

目录 前言 方法一、遍历链表两次 方法二、遍历链表一次&#xff08;前后双指针&#xff09; 前言 题目链接&#xff1a;LCR 021. 删除链表的倒数第 N 个结点 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 如果给定一个链表&#xff0c;请问如何删除链表中的…

ThinkPad T14/T15/P14s/P15s gen2电脑原厂Win10系统镜像 恢复笔记本出厂时预装自带OEM系统

lenovo联想原装出厂Windows10系统&#xff0c;适用型号&#xff1a; ThinkPad T14 Gen 2&#xff0c;ThinPad T15 Gen 2&#xff0c;ThinkPad P14s Gen 2&#xff0c;ThinkPad P15s Gen 2 &#xff08;20W1,20W5,20VY,20W7,20W0,20W4,20VX,20W6&#xff09; 链接&#xff1…

BO、VO层应用实例

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; BO、VO层应用实例 BO&#xff08;Business Object&#xff09;层是一种用于处理业务逻辑的组件层。BO层主要负责封装和处理与业务相关的逻辑和数据操作&#xff0c;它…

web前端项目-超级玛丽【附源码】

超级玛丽 【超级玛丽】是一个基于HTML5和JavaScript开发的经典电子游戏。玩家需要控制主角马里奥在各种关卡中跳跃、奔跑、消灭敌人&#xff0c;以完成游戏目标。玩家通过浏览器可以体验经典的超级玛丽关卡和冒险。 运行效果&#xff1a;方向键控制马里奥的左右移动、跳跃、奔…

【Unity学习笔记】第十二 · New Input System 及其系统结构 和 源码浅析

转载请注明出处&#xff1a;&#x1f517;https://blog.csdn.net/weixin_44013533/article/details/132534422 作者&#xff1a;CSDN|Ringleader| 主要参考&#xff1a; 官方文档&#xff1a;Unity官方Input System手册与API官方测试用例&#xff1a;Unity-Technologies/InputS…

大语言模型无代码构建知识图谱(2)--环境准备

软件环境 需已安装MySQL数据库。需已安装HuggingFists系统&#xff0c;该系统将提供无代码的可视化数据开发环境。通过该系统利用大语言模型辅助知识图谱的构建。HuggingFists系统的安装可参考《HuggingFists-低代码玩转LLM RAG-准备篇》 流程环境 数据文件 进入HuggingFis…

源码透析MapperScannerRegistrar和MapperScannerConfigurer的区别及作用

文章目录 前言MapperScannerRegistrar使用方式实现原理 MapperScannerConfigurer使用方式实现原理 两者区别对比源码解析MapperScannerRegistrarMapperScannerConfigurerMapperFactoryBean 总结 本文里面涉及到的相关文章 MapperScan注解里面涉及到的Import注解解析可以查看系…

Flutter:跨平台移动应用开发的未来

Flutter&#xff1a;跨平台移动应用开发的未来 引言 Flutter的背景和概述 Flutter是由Google开发的一个开源UI工具包&#xff0c;用于构建漂亮、快速且高度可定制的移动应用程序。它于2017年首次发布&#xff0c;并迅速引起了开发者们的关注。Flutter采用了一种全新的方法来…

pip install flagai时出现Collecting PyYAML==5.4.1 (from flagai)等错误信息的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

7.【CPP】String类

一.汉字的编码 我们知道计算机存储英文字母&#xff0c;标点&#xff0c;数字用的是ascall码&#xff0c;128种用一个字节表示绰绰有余。而汉字远远不止128种&#xff0c;因此汉字需要两个字节表示。 1.gbk编码中汉字占两个字节。 2.utf-8中&#xff0c;一个汉字占三个字节。…

Oracle Linux 6.10 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

第十回 朱贵水亭施号箭 林冲雪夜上梁山-FreeBSD/Linux 控制台基础操作

林冲被众庄客捉住&#xff0c;吊在门楼下&#xff0c;正被打时&#xff0c;柴进来了&#xff0c;赶快把林冲救下来。原来这是柴进打猎用的小庄子&#xff0c; 林冲就把火烧草料场一事跟柴进详细的说了。柴进说兄弟真是命运多磨难啊。林冲住了几日&#xff0c;恐怕连累柴进&…