实现顺序表的增删查改

news2024/11/23 21:26:01

现在让我们探索数据结构这个美妙的世界吧!

概念介绍

线性表是具有相同特性的数据元素的有限序列。线性表是一种在实际运用中广泛运用的线性结构,如线性表,栈,队列,字符串等。

顺序表的本质是数组,实现了对数组的封装,例如增删查改等功能。

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

静态顺序表:

#define N 100
struct SeqList
{
    int arr[N];
    int size;//有效数据个数
};

动态顺序表:

struct SeqList
{
     int* arr;//动态数组
     int size;//有效数据个数
     int capacity;//空间大小
};

但是目前这个结构体只能存储int类型的数据,所以我们给数据类型起一个别名,让其更好存储其他类型的数据。

我们当前顺序表存储的类型进行替换:

typedef int SLDataType;

当前顺序表被我们修改成这样:

struct SeqList
{
     SLDataType* arr;//动态数组
     int size;//有效数据个数
     int capacity;//空间大小
};

但是每次引用我们的顺序表时,我们都要写SeqList,这样未免太麻烦了,于是我们想到用typedef一下来缩减我们的工作量。

typedef struct SeqList SL;

或者我们还可以采用另一种方式:

typedef struct SeqList
{
     SLDataType* arr;//动态数组
     int size;//有效数据个数
     int capacity;//空间大小
}SL;

初始化

void SLInit(SL* ps);
void SLInit(SL s)
{
   s.arr=NULL;
   s.size=s.capcity=0;
}

我们测试一下顺序表初始化的一些方法:

void SLTest01()
{
   SL s1;
   SLInit(s1);
}

int main()
{
   SLTest01();
   return 0;
}

这个程序初始化的结果竟然是错误的,那么问题出现在哪里呢?问题在于我们没有传地址,仅仅是传值调用了。那就让我们修改一下我们的代码吧。

void SLInit(SL* ps);
void SLInit(SL* ps)
{
   s.arr=NULL;
   s.size=s.capcity=0;
}
void SLTest01()
{
   SL s1;
   SLInit(&s1);
}

int main()
{
   SLTest01();
   return 0;
}

销毁

void SLDestroy(SL* ps);
void SLDestroy(SL* ps)
{
   if(ps->arr)
   {
      free(ps->arr);
   }
   ps->arr=NULL;
   ps->size=ps->capcity=0;
}

尾部插入

void SLPushBack(SL* ps, SLDataType x);//往哪儿插入未知,所以要传入结构体

如图所示,size从4变成了5。

void SLPushBack(SL* ps, SLDataType x)
{
  //我们要往size里面插入x
   ps->arr[size++]=x;//size后置加加,完成这个式子以后,size的空间被扩展
}

插入完成之后,让我们测试一下这个函数吧。

void SLTest01()
{
  SL s1;
  SLPushBack(&s1,1);
}

 但是测试的结果竟然是错误的,这是为啥呢?

空间为0,不能往数组里插入数据。在插入数据之前,我们应该先检查空间够不够。

void SLPushBack(SL* ps, SLDataType x)
{
  //我们要往size里面插入x
   if(ps->capacity=ps->size)
   {
     //申请空间,增容通常是成倍地增加
     //如果malloc失败,会返回空指针
   int newCapacity=ps->capacity==0?4:2*ps->capacity;
     //我们再把申请来的空间给临时的tmp
   SLDataType*tmp=(SLDataType*)realloc(ps->arr,newCapacity*sizeof(SLDataTpye);
   if(tmp==NULL)
   {
       perror("realloc fail");
       exit(1);//直接退出程序,不再执行
    }
   ps->arr=tmp;//如果开辟成功,就把realloc出的新空间给arr
   ps->capacity=newCapacity;
     
   ps->arr[size++]=x;//size后置加加,完成这个式子以后,size的空间被扩展
}

如果我们插入空(NULL),这个程序就崩了。说明这个代码还不具备健壮性

那么我们可以如何解决呢?

if(ps==NULL)
{
   return;
}

这样遇到空,程序就会结束。我们也可以换一种方式:

assert(ps);

等价于assert(ps!=NULL);   这时如果为空,就直接一个弹窗出来报错了。

头部插入

void SLPushFront(SL* ps, SLDataType x);

插入数据我们就想到空间是否够用呢?

void SLPushFront(SL* ps, SLDataType x)
{
    assert(ps);//检查ps是否为空
    SLCheckCapacity(ps);
    //先让顺序表向后挪动一位
    for(int i=ps->size;i>0;i--)
    //要判断函数的终止条件,就要看最后一个移动的条件是什么?这个程序是从后往前挪动,那么最后一次挪动就是arr[0]挪动到arr[1],那么i等于1,i大于0
    {
       ps->arr[i]=ps->arr[i-1];
     }
     ps->arr[0]=x;
     ps->size++;
}

在我们检查函数空间大小是否够用时,我们可以单独封装一个函数。

void SLCheckCapacity(SL*ps)
{
  //我们要往size里面插入x
   if(ps->capacity=ps->size)
   {
     //申请空间,增容通常是成倍地增加
     //如果malloc失败,会返回空指针
   int newCapacity=ps->capacity==0?4:2*ps->capacity;
     //我们再把申请来的空间给临时的tmp
   SLDataType*tmp=(SLDataType*)realloc(ps->arr,newCapacity*sizeof(SLDataTpye));
   if(tmp==NULL)
   {
       perror("realloc fail");
       exit(1);//直接退出程序,不再执行
    }
   ps->arr=tmp;//如果开辟成功,就把realloc出的新空间给arr
   ps->capacity=newCapacity;
}

当我们运行完一个程序时,打印一下查看结果是否正确。

void Print(SL s)
{
   for(int i=0;i<s.size;i++)
   {
      printf("%d",s.arr[i]);
   }
   printf("\n");
}

出乎意料的是,打印的结果不是我们想要的:

 好吧,增加一个数据,我们的size忘了++了。

尾部删除

void SLPopBack(SL*PS)
{
//ps不能为空,所以要先判断一下
   assert(ps);
   assert(ps->size);//数据个数也不能为空
   ps->arr[size-1]=-1;
   --ps->size;
}

直接把size--,不影响增删查改数据。

头部删除

void SLPopFront(SL*ps)
{
   assert(ps);
   assert(ps->size);
   for(int i=0;i<ps->size-1;i++)
   {
      ps->arr[i]=ps->arr[i+1];//arr[size-1]=arr[size-2]
   }
   ps->size--;
}

在指定位置之前插入数据

void SLInsert(SL*ps,int pos,SLDataType x)
{
    assert(pos);
    assert(pos>=0&&pos<=ps->size);//可以等于,可以在size之前插入数据,在这里也就是尾插

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

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

相关文章

微信小程序使用icon图标

原因&#xff1a; 微信小程序使用fontawesome库使用icon图标&#xff0c;网上有很多教程&#xff0c;按照网上说法制作&#xff0c;引入到微信小程序中&#xff0c;但是验证成功&#xff0c;只能使用部分图标&#xff0c;结果不尽如人意。后面使用阿里巴巴开源iconfont来使用ic…

DBU-Net:用于乳腺超声图像中肿瘤分割的双分支U形网络

DBU-Net&#xff1a;用于乳腺超声图像中肿瘤分割的双分支U形网络 摘要引言材料和方法概述所提出的方法 DBU-Net Dual branch U-Net for tumor segmentation in breast ultrasound images 摘要 乳腺超声医学图像通常具有低成像质量沿着不清楚的目标边界。这些问题使得医生在诊断…

VSCode调试C++

1、环境准备 1.1、g的安装与使用 1.1.1、安装 方式一&#xff1a;Xcode安装 苹果的开发集成工具是Xcode.app&#xff0c;其中包含一堆命令行工具。 在 App store 可以看到其大小有好几个G&#xff0c;有点大。 方式二&#xff1a;Command Line Tools 安装 Command Line Too…

Ai音乐大师演示(支持H5、小程序)独立部署源码

Ai音乐大师演示&#xff08;支持H5、小程序&#xff09;独立部署源码

【开发问题】为什么Java写文件时文件名中带有“*”会写入失败呢?

前言&#xff1a;在开发过程中&#xff0c;可能会遇写文件的问题。当我们写文件时&#xff0c;文件名中可能会带“*”号。这时候可能会导致写文件失败。 比如有一段写文件的代码&#xff1a; public static void createFile(String filename, byte[] content) {FileOutputStr…

蓝桥杯刷题-四平方和

四平方和 代码&#xff1a; from copy import deepcopy n int(input()) maxn int(5e6) 10 dic dict() for a in range(maxn):if a * a > n:breakfor b in range(a,maxn):if a * a b * b > n:breakif dic.get(a*ab*b) is None:dic[a*ab*b] (a,b) ans [maxn for _ …

情感视频素材在哪找?8个视频素材大全网站

在追求创意表达的道路上&#xff0c;每一位视频创作者都是一名勇敢的探险家&#xff0c;不断寻找那些能够点亮作品、让故事生动起来的珍贵资源。无论你的目标是打动人心、传达信息&#xff0c;还是简单地分享生活&#xff0c;以下八个视频素材网站将为你的每一个项目提供无尽的…

【C++第三阶段】模板类模板通用数组实现案例

以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 模板怎么使用模板函数模板注意事项普通函数与函数模板的区别普通函数与函数模板调用规则函数模板限制 类模板类模板语法类模板与函数模板区别类模板中成员函数创建时机类模板对象做函…

Linux网络协议栈从应用层到内核层④

文章目录 1、网卡接受数据2、网络设备层接收数据3、ip层接受数据4、tcp层接受数据5、上层应用读取数据6、数据从网卡到应用层的整体流程 1、网卡接受数据 当网卡收到数据时&#xff0c;会触发一个中断&#xff0c;然后就会调用对应的中断处理函数&#xff0c;再做进一步处理。…

WSL安装与使用

开启之后&#xff0c;会提示你重启电脑才能使配置生效&#xff0c;我们重启即可。 电脑重启后&#xff0c;打开Microsoft Store搜索WSL&#xff0c;既可以看到支持的操作系统&#xff0c;我们选择Ubuntu即可&#xff0c;我们选择第一个就可以。 随后我们打开&#xff0c;发现报…

【WebKit架构讲解】

&#x1f308;个人主页:程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

开源知识管理和协作平台:插件丰富,主题精美 | 开源日报 No.209

logseq/logseq Stars: 27.8k License: AGPL-3.0 logseq 是一个注重隐私的开源平台&#xff0c;用于知识管理和协作。 提供强大的知识管理、协作、PDF 标注和任务管理工具支持多种文件格式&#xff0c;包括 Markdown 和 Org-modeWhiteboard 功能可使用空间画布组织想法&#x…

vue源码解析——vue如何将template转换为render函数

Vue 将模板&#xff08;template&#xff09;转换为渲染函数&#xff08;render function&#xff09;是 Vue 编译器的核心功能&#xff0c;它是 Vue 实现响应式和虚拟 DOM 的关键步骤。在 Vue 中&#xff0c;模板&#xff08;template&#xff09;是开发者编写的类似 HTML 的代…

SAP FI学习笔记03 - 应付账款

上一章讲了MM与FICO的集成。 SAP FI学习笔记02 - 基础知识 - MM与FICO集成-CSDN博客 本章讲应付账款。 上一章也讲了应付账款&#xff08;買掛金&#xff09;&#xff0c;它的来源可以是 - 购买发注&#xff0c;入库&#xff0c;请求书照合 之后系统自动生成 &#xff08;具…

南京大学提出用于大模型生成的动态温度采样法,简单有效!

在自然语言处理&#xff08;NLP&#xff09;的领域&#xff0c;大语言模型&#xff08;LLMs&#xff09;已经在各种下游语言任务中展现出了卓越的性能。这些任务包括但不限于问答、摘要、机器翻译等。LLMs的强大能力在于其生成的文本质量和多样性。为了控制生成过程&#xff0c…

任意文件下载漏洞

1.文件下载漏洞存在的位置 文件经过php处理可能存在文件下载漏洞&#xff0c;配合目录遍历漏洞使用 2.目录遍历漏洞检验方法 测试是否存在目录遍历漏洞&#xff1a;在网站网址中间添加随意写一个文件名../&#xff08;返回上一级&#xff09;进行测试&#xff0c;没有报错就…

UART通信

UART——通用异步收发传输器&#xff0c;UART 作为异步串口通信协议的一种&#xff0c;工作原理是将传输数据的每个字符一位接一位地传输。在应用程序开发过程中使用频率较高的数据总线。 基于UART的数据传输是异步形式的串行数据传输。基于UART的串行数据传输不需要使用时钟信…

基于springboot+vue实现的酒店客房管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

[Python学习篇] Python创建项目

新建项目 打开开发工具 PyCharm 选择 New Project 目录结构如下 运行 hello world 选中项目&#xff0c;右键 New -> Python File 进行创建文件 运行项目

STM32学习和实践笔记(4): 分析和理解GPIO_InitTypeDef GPIO_InitStructure (b)

继续上篇博文&#xff1a;STM32学习和实践笔记&#xff08;4&#xff09;: 分析和理解GPIO_InitTypeDef GPIO_InitStructure (a)-CSDN博客 往下写&#xff0c; 为什么&#xff1a;当GPIO_InitStructure.GPIO_PinGPIO_Pin_0 ; 时&#xff0c;其实就是将对应的该引脚的寄存器地…