【手撕数据结构】把玩顺序表

目录

  • 顺序表介绍
  • 初始化顺序表
  • 销毁顺序表
  • 打印顺序表
  • 增加数据
    • 头插
    • 尾插
    • 指定位置下标插入
  • 删除顺序表元素
    • 尾删
    • 头删
    • 指定位置删除

顺序表介绍

顺序表是⽤⼀段物理地址连续的存储单元依次存储数据元素的线性结构,⼀般情况下采⽤数组

线性结构又是什么意思,这就不得不提到线性表了

线性表(linear list)是n个具有相同特性的数据元素的有限序列线性表是⼀种在实际中⼴泛使 ⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串

注意的是,他在逻辑结构上一定是连续的,但在物理结构上不一定是连续的.线性
表在物理上存储时,通常以数组和链式结构的形式存储

那么我们知道,数组在内存中存储也是连续的,并且也是类型一致,那么他与顺序表的区别是什么呢.

  • 顺序表的底层结构是数组,对数组的封装,实现了常⽤的增删改查等接⼝
  • 顺序表的长度可以动态增长,普通数组的长度是固定的。

初始化顺序表

首先,我们要创建一个顺序表类型,该顺序表类型包括了顺序表的起始位置、记录顺序表内已有元素个数的计数器(size),以及记录当前顺序表的容量的变量(capacity)。

typedef int SLDataType;//本篇博客以存放整型数据为例typedef struct SeqList
{SLDataType* a;//声明了一个指向顺序表的指针,姑且称它为“顺序表指针”int size;//记录当前顺序表内元素个数int capacity;//记录当前顺序表的最大容量
}SeqList;

然后,我们需要一个初始化函数,对顺序表进行初始化。

//初始化顺序表
void SeqListInit(SeqList* ps)
{assert(ps);ps->a = NULL;//刚开始时顺序表为空,顺序表指针为NULLps->size = 0;//起始时元素个数为0ps->capacity = 0;//容量为0
}

销毁顺序表

因为顺序表所用的内存空间是动态开辟在堆区的,所以我们在使用完后需要及时对其进行释放,避免造成内存

//销毁顺序表
void SeqListDestory(SeqList* ps)
{assert(ps);free(ps->a);//释放顺序表指针指向的空间ps->a = NULL;//及时置空ps->size = 0;//元素个数置0ps->capacity = 0;//容量置0
}

若需要对数据进行保存,可以使用文件操作函数将数据保存到一个文件中,下次使用顺序表的时候先读取文件数据即可

打印顺序表

void SeqListPrint(SeqList ps)	//注意这里我们最好不要使用指针接受,因为我们不改值
{assert(ps);int i = 0;//循环打印顺序表指针指向的数据for (i = 0; i < ps.size; i++){printf("%d ", ps.a[i]);}printf("\n");
}

增加数据

仔细想一想,我们每次增加数据的时候是不是应该都要检查一下存储数据的空间是否还足够存储增加的数据,如果不够我们是不是又要申请一块内存空间来存储数据,那一块一块的申请吗,是不是有点太麻烦了。所以由数学推理,这里最好每次申请原空间的2倍或3倍

//检查顺序表容量是否已满,若已满,则增容
void SeqCheckCapacity(SeqList* ps)
{if (ps->size == ps->capacity)//满了,需要增容{//判断顺序表容量是否为0,若为0,则先开辟用于存放4个元素的空间大小,若不为0,则扩容为原来容量的两倍int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* newA = realloc(ps->a, newcapacity*sizeof(SLDataType));if (newA == NULL){printf("realloc fail\n");exit(-1);}ps->a = newA;//开辟成功,将顺序表指针更新ps->capacity = newcapacity;//容量更新}
}

头插

要想在顺序表的表头插入数据,那么就需要先将顺序表原有的数据从后往前依次向后挪动一位,最后再将数据插入表头

//头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{assert(ps);SeqCheckCapacity(ps);//检查容量int i = 0;for (i = ps->size; i > 0; i--)//将数据从后往前依次向后挪{ps->a[i] = ps->a[i - 1];}ps->a[0] = x;ps->size++;//顺序表元素个数加一
}

注意:注意:挪动数据的时候应从后向前依次挪动,若从前向后挪动,会导致后一个数据被覆盖。

尾插

尾插相对于头插就比较简单了,直接在表尾插入数据即可。

//尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{assert(ps);SeqCheckCapacity(ps);//检查容量,这里一定要注意传ps,而不是传&ps,&ps是二级指针,且穿过去会初始化一个随机值,ps->a[ps->size] = x;ps->size++;//顺序表元素个数加一
}

指定位置下标插入

void SLInsert(SL* ps, SLDataType x, int pos)
{assert(ps);//assert(pos >= 0 && pos < ps->size);assert(pos >= 0 && pos <= ps->size);	//这里之所以可以pos<=ps->size,因为我们是在之前插,这里就相当于是尾插CheckCapacity(ps);for (int i = ps->size; i >pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;++ps->size;
}

这里与上面的尾插和头插异曲同工,要注意的是pos的值是可以=ps->size的,当他在size的位置前插入的时候就相当于是尾插,然后根据从ps->size从后向前覆盖移动,直到i等于pos结束,这里i>pos,是因为我们要通过arr[i-1]来赋值,当pos等于0时i最小值是在1,也就是取到最小的下标就是1-1=0,不会造成段错误(数组越界).

删除顺序表元素

尾删

void SLPopBack(SL* ps)
{assert(ps);assert(ps->size);	//顺序表得有有效的数据才能删除ps->size--;	//只要减去有效数据个数不管是后面插入还是打印都不影响,插入都可以通过在size的下一个位置直接插入覆盖元数据}

这里肯定有人会疑惑为什么直接把size–就可以了,而不是把要删除数据的内存空间释放了,大可不必,我们建立顺序表就是为了使用增删查改的方法,而这些方法几乎都和我们size成员,即有效成员个数挂钩,比如说是打印方法,我们最多打印到ps->size个数据,头/尾插,我们在从size下标那里开始插入,所以我们–size就相当于删除了一个数据,即使是再次插入那个位置的数据,也不会影响结果,因为我们可以直接覆盖原来的数据.

头删

void SLPopFront(SL* ps)
{assert(ps);assert(ps->size);/*if (ps->size == 1){ps->arr = NULL;ps->size--;}else{*///这里之所以前面不进行单独只有一个节点判断,同尾删一样,即使下面把尾删的数据赋值到arr[0],下次插入数据时会覆盖for (int i = 0; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}--ps->size;
}

这里不用说了,与尾删一样

指定位置删除

void SLErase(SL* ps, int pos)
{assert(ps);assert(ps->size);assert(pos >= 0 && pos < ps->size);for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}--ps->size;
}

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

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

相关文章

【性能优化】在大批量数据下使用 HTML+CSS实现走马灯,防止页面卡顿(一)

切换效果 页面结构变化 1.需求背景 项目首页存有一个小的轮播模块,保密原因大概只能这么展示,左侧图片右侧文字,后端一次性返回几百条数据(开发环境下,生产环境只会更多).无法使用分页解决,前端需要懒加载防止页面卡顿 写个小demo演示,如下 2.解决思路 获取到数据后,取第一…

二、链表(2)

24. 两两交换链表中的节点 法一&#xff1a;迭代&#xff0c;while循环&#xff0c;注意要获取next给变量&#xff0c;得先判断非null, 需要4个变量&#xff0c; n0是前&#xff0c;n1 n2是交换的两&#xff0c;n3是n2的下一个可能为空&#xff0c;这种先把变量保存起来&#…

Leetcode1688. 比赛中的配对次数

问题描述&#xff1a; 给你一个整数 n &#xff0c;表示比赛中的队伍数。比赛遵循一种独特的赛制&#xff1a; 如果当前队伍数是 偶数 &#xff0c;那么每支队伍都会与另一支队伍配对。总共进行 n / 2 场比赛&#xff0c;且产生 n / 2 支队伍进入下一轮。如果当前队伍数为 奇…

接口测试总结(非标准)

为什么要做接口测试&#xff1f; 答&#xff1a;接口测试是为了检测系统组件间接口的正确性和稳定性&#xff0c;以及检查数据的交换、传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。接口测试可以帮助我们发现系统中的潜在问题&#xff0c;确保系统的稳定性…

CSP-J模拟赛day1

yjq的吉祥数 文件读写 输入文件 a v o i d . i n avoid.in avoid.in 输出文件 a v o i d . o u t avoid.out avoid.out 限制 1000ms 512MB 题目描述 众所周知&#xff0c; 这个数字在有些时候不是很吉利&#xff0c;因为它谐音为 “散” 所以yjq认为只要是 的整数次幂的数…

JavaWeb连接(JDBC)数据库实现增删改查

JavaWeb连接(JDBC)数据库实现增删改查 1、数据库结构 (1)、创建数据库&#xff08;source_db&#xff09; (2)、创建数据表&#xff08;tb_source&#xff09;&#xff0c;结构如下 字段名说明字段类型长度备注id编号int主键&#xff0c;自增&#xff0c;增量为 1name名称v…

前端面试 vue 按钮级的权限控制

方案一 按钮权限也可以用v-if判断 但是如果页面过多&#xff0c;每个页面页面都要获取用户权限role和路由表里的meta.btnPermissions&#xff0c;然后再做判断 这种方式就不展开举例了 方案二 使用自定义指令实现 按钮级的权限控制 思维导图 心就是自定义指令的书写 首先…

【算法】TopK问题超详解

TopK算法 TopK问题基本框架就是&#xff1a; 从n个数中&#xff0c;找出最大&#xff08;或最小&#xff09;的前k个数。 在我们生活中&#xff0c;经常会遇到TopK问题 比如大众点评的必吃榜&#xff1b;成绩单的前十名&#xff1b;各种数据的最值筛选&#xff1b; [外链图片…

【人工智能】Transformers之Pipeline(四):零样本音频分类(zero-shot-audio-classification)

​​​​​​​ 目录 一、引言 二、零样本音频分类&#xff08;zero-shot-audio-classification&#xff09; 2.1 概述 2.2 意义 2.3 应用场景 2.4 pipeline参数 2.4.1 pipeline对象实例化参数​​​​​​​ 2.4.2 pipeline对象使用参数 2.4 pipeline实战 2.5 模…

【MySQL】:对库和表的基本操作方法

数据库使用的介绍 什么是SQL 学习数据库的使用——>基于 SQL编程语言 来对数据库进行操作 重点表述的是“需求”&#xff0c;期望得到什么结果。&#xff08;至于结果是如何得到的&#xff0c;并不关键&#xff0c;都是数据库服务器在背后做好了&#xff09; 重点表述的是…

线程之间的通信

第一题 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdarg.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <dirent.h> #include <…

蔡司小乐圆:护航青少年视力健康,专业应对近视挑战

在科技日新月异的今天&#xff0c;电子产品已深度融入青少年的日常&#xff0c;为生活带来便利的同时&#xff0c;也悄然间对他们的视力构成了威胁。近视&#xff0c;这一日益严峻的健康问题&#xff0c;正牵动着无数家庭的心弦。蔡司眼镜&#xff0c;作为眼镜行业的领军者&…

7月21日,贪心练习

大家好呀&#xff0c;今天带来一些贪心算法的应用解题、 一&#xff0c;柠檬水找零 . - 力扣&#xff08;LeetCode&#xff09; 解析&#xff1a; 本题的贪心体现在对于20美元的处理上&#xff0c;我们总是优先把功能较少的10元作为找零&#xff0c;这样可以让5元用处更大 …

代码随想录算法训练营第35天|LeetCode 01背包问题 二维、01背包问题 一维、416. 分割等和子集

1. LeetCode 01背包问题 二维 题目链接&#xff1a;https://kamacoder.com/problempage.php?pid1046 文章链接&#xff1a;https://programmercarl.com/背包理论基础01背包-1.html#算法公开课 视频链接&#xff1a;https://www.bilibili.com/video/BV1cg411g7Y6/ 思路&#xf…

面向对象三大特征及其优劣接口的特点、抽象类的特点

简单介绍下面向对象三大特征&#xff1f; 封装&#xff1a;封装指的就是把对象的属性隐藏在内部&#xff0c;不允许外部对象直接访问内部信息&#xff0c;但是可以提供一些被外界访问的方法来访问属性。优点在于数据隐藏&#xff08;通过定义私有属性&#xff0c;避免直接访问…

JavaScript银行卡实名核验接口集成 代码详解

银行卡实名核验接口是一种用于验证银行卡持有人身份的服务&#xff0c;通常应用于金融机构或第三方支付平台。这种接口允许应用程序或服务发送请求&#xff0c;以验证银行卡所有者的身份信息是否与银行记录相匹配。 应对市场发展需求&#xff0c;翔云提供了银行卡实名认证接口…

压缩pdf大小的方法 指定大小软件且清晰

在数字化时代&#xff0c;pdf文件因其良好的兼容性和稳定性&#xff0c;已成为文档分享的主流格式。然而&#xff0c;高版本的pdf文件往往体积较大&#xff0c;传输和存储都相对困难。本文将为您详细介绍几种简单有效的方法&#xff0c;帮助您减小pdf文件的大小&#xff0c;让您…

Gradle构建配置包:一键生成构建脚本的秘籍

标题&#xff1a;Gradle构建配置包&#xff1a;一键生成构建脚本的秘籍 在软件开发过程中&#xff0c;构建系统是项目自动化构建的核心。Gradle&#xff0c;作为一种流行的构建自动化工具&#xff0c;以其灵活性和强大的扩展性而广受开发者欢迎。Gradle构建配置包&#xff08;…

任务3 git基础知识(主要是pr的笔记)

任务要求 https://github.com/InternLM/Tutorial/blob/camp3/docs/L0/Git/task.md 文档 https://github.com/InternLM/Tutorial/blob/camp3/docs/L0/Git/readme.md 任务 任务1&#xff1a;提交PR https://github.com/InternLM/Tutorial/pull/1242 任务2&#xff1a;实践…

UML的六大关系---泛化、实现、关联、聚合、组合、依赖

文章目录 前言1. 泛化关系(Generalization)2. 实现关系(Realization)3. ‌关联关系(Association)4. 聚合关系(Aggregation)5. 组合关系(Composition)6. 依赖关系(Dependency)总结 前言 讲到设计模式&#xff0c;就会有 U M L UML UML类图这个东西。 一开始就很难理解各种线啥意…