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

别丢了你的勇敢

前言:

自今日起,我们正式越过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.mzph.cn/news/638635.shtml

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

相关文章

MyBatis 使用报错: Can‘t generate mapping method with primitive return type

文章目录 前言问题原因解决方案个人简介 前言 今天在新项目中使用 MyBatis 报如下错误&#xff1a;Cant generate mapping method with primitive return type 问题原因 发现是 Mapper 注解引入错误&#xff0c;错误引入 org.mapstruct.Mapper, 实际应该引入 org.apache.ibat…

接口测试 04 -- Jsonpath断言、接口关联处理

1. JsonPath基本介绍 1.1 JsonPath简介 JsonPath是一种用于在JSON数据中定位和提取特定数据的表达式语言。它类似于XPath用于XML的定位和提取&#xff0c;可以帮助我们灵活地从复杂的JSON结构中获取所需的数据。 1.2 JsonPath的特点 ● JsonPath可处理的报文类型为字典类型 …

4.servera修改主机名,配置网络,以及在cmd中远程登录servera的操作

1.先关闭这两节省资源 2.对于新主机修改主机名&#xff0c;配置网络 一、配置网络 1.推荐图形化界面nmtui 修改完成后测试 在redhat ping一下 在redhat远程登录severa 2、使用nmcli来修改网络配置 2.1、配置要求&#xff1a;主机名&#xff1a; node1.domain250.exam…

C++:类与对象(上)

C&#xff1a;类与对象&#xff08;上&#xff09; 类的引入类的定义访问限定符类域实例化对象模型this指针 类的引入 C的类是基于C语言的结构体优化出来的&#xff0c;那我们先来看一看C对结构体有哪些优化点。 C语言与C的结构体的类型名称略有区别&#xff0c;我们看一个案…

寒假每日一题-小苹果

小 Y 的桌子上放着 n 个苹果从左到右排成一列&#xff0c;编号为从 1 到 n。 小苞是小 Y的好朋友&#xff0c;每天她都会从中拿走一些苹果。 每天在拿的时候&#xff0c;小苞都是从左侧第 1个苹果开始、每隔 2 个苹果拿走 1个苹果。 随后小苞会将剩下的苹果按原先的顺序重新…

【Leetcode】接雨水(双指针、单调栈)

目录 &#x1f4a1;题目描述 &#x1f4a1;双指针解法 &#x1f4a1;单调栈解法 &#x1f4a1;题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 提示&#xff1a; n height.length1 < n…

010-新手如何建立一个属于自己的图像处理FPGA/ZYNQ框架(自己的用着才舒服,内容非常全面!)

文章目录 前言一、图像处理框架二、图像采集输入1.常用视频流格式&#xff1a;Rgb565/Bayer1.RGB565数据流格式2.Bayer阵列数据流格式 2.图像预处理&#xff1a;时钟域同步/去马赛克/色彩空间转换/滤波1.时钟域同步2.图像去马赛克化3.色彩空间转换4.滤波 三、图像算法处理1.图像…

【后端】深入浅出Node.js

文章目录 1.Node简介1.1 诞生历程1.2 阻塞IO和异步IO 【后端目录贴】 1.Node简介 1.1 诞生历程 Node特点 事件驱动、非阻塞I/O node和chrome浏览器区别 除了HTML、WebKit和显卡这些UI相关技术没有支持外&#xff0c;Node结构与Chrome十分相似&#xff0c;他们都是基于事件驱动…

Vue 组件通信方式

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

AI大模型开发架构设计(1)——LLM大模型Agent剖析和应用案例实战

文章目录 LLM大模型Agent剖析和应用案例实战1 从 LLM 大模型到智能体演进技术语言模型是什么&#xff1f;大语音模型是什么&#xff1f;大语言模型日新月异LLM大模型存在局限性LLM Agent来势凶凶LLM Agent增长迅猛LLM Agent是什么&#xff1f; 2 LLM Agent 架构深度剖析规划能力…

OpenCV实战——OpenCV.js介绍

OpenCV实战——OpenCV.js介绍 0. 前言1. OpenCV.js 简介2. 网页编写3. 调用 OpenCV.js 库4. 完整代码相关链接 0. 前言 本节介绍如何使用 JavaScript 通过 OpenCV 开发计算机视觉算法。在 OpenCV.js 之前&#xff0c;如果想要在 Web 上执行一些计算机视觉任务&#xff0c;必须…

线性代数:矩阵运算(加减、数乘、乘法、幂、除、转置)

目录 加减 数乘 矩阵与矩阵相乘 矩阵的幂 矩阵转置 方阵的行列式 方阵的行列式&#xff0c;证明&#xff1a;|AB| |A| |B| 加减 数乘 矩阵与矩阵相乘 矩阵的幂 矩阵转置 方阵的行列式 方阵的行列式&#xff0c;证明&#xff1a;|AB| |A| |B|

核密度曲线(python

目录 1.代码&#xff1a;2.效果&#xff1a;小结&#xff1a; 1.代码&#xff1a; import pandas as pd import matplotlib.pyplot as plt # 读入数据 file r123.xlsx sheet Sheet2 col S213 # 标题名称 title col 供订比曲线 xlabel 供订比 # 横轴显示范围 xleft 0 xr…

解决 conda新建虚拟环境只有一个conda-meta文件&conda新建虚拟环境不干净

像以前一样通过conda 新建虚拟环境时发现环境一团糟&#xff0c;首先新建虚拟环境 conda create -n newenv这时候activate newenv&#xff0c;通过pip list&#xff0c;会发现有很多很多的包&#xff0c;都是我在其他环境用到的。但诡异的是&#xff0c;来到anaconda下env的目…

加固密码安全:保护您的个人信息

一、引言 在数字化时代&#xff0c;密码安全是保护个人信息和数据的重要环节。然而&#xff0c;许多人在创建和管理密码时存在一些常见的安全漏洞&#xff0c;如使用弱密码、重复使用密码等。本文将详细介绍密码安全的重要性&#xff0c;并提供一些有效的方法和技巧&#xff0…

【嘉立创EDA-PCB设计指南】4.模块化布局

前言&#xff1a;本文对本专栏中的【嘉立创EDA-PCB设计指南】前面绘制的原理图进行模块化布局&#xff0c;首先进行预布局&#xff08;将每个模块放一起&#xff09;&#xff0c;然后进行精细化布局&#xff08;按照原理图来精细化布局&#xff09;。 目录 模块化预布局 模块…

软件工程应用题汇总

绘制数据流图(L0/L1/L2) DFD/L0&#xff08;基本系统模型&#xff09; 只包含源点终点和一个处理(XXX系统) DFD/L1&#xff08;功能级数据流图&#xff09;在L0基础上进一步划分处理(XXX系统) 个人理解 DFD/L2&#xff08;在L1基础上进一步分解后的数据流图&#xff09; 数据…

NumPy2要来了,但先别急!

B站&#xff1a;啥都会一点的研究生公众号&#xff1a;啥都会一点的研究生 如果你正在使用 Python 编写代码&#xff0c;那么很有可能正在直接或间接地使用 NumPy 如Pandas、Scikit-Image、SciPy、Scikit-Learn、AstroPy…这些都依赖于 NumPy NumPy 2 是一个新的重要版本&am…

XXE漏洞概念

1、XXE漏洞概念 XXE(XML External Entity Injection) 又称为XML外部实体注入。 XML是一种类似于HTML&#xff08;超文本标记语言&#xff09;的可扩展标记语言&#xff0c;是用于标记电子文件使其具有结构性的标记语言&#xff0c;可以用来标记数据、定义数据类型&#xff0c…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-7 datalist

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>datalist</title> </head><body> <input id"address" list"addressList"> <datalist id"addressList"…