详解初阶数据结构之顺序表(SeqList)——单文件文件实现SeqList的增删查改
目录
一、线性表
二、顺序表
2.1概念及结构
2.2接口实现
2.3动态顺序表的创建
2.3动态顺序表的初始化
2.3.1传值初始化
2.3.2传址初始化
2.4动态顺序表的清空
2.5动态顺序表的扩容
2.6动态顺序表内容的打印
三、动态顺序表的使用
3.1尾插尾删
3.1.1尾插
3.1.2尾删
3.2头插头删
3.2.1头插
3.2.2头删
3.3在pos位置插入x
3.4删除pos位置的值
3.5修改某个位置的值
四、完整代码
一、线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。

二、顺序表
2.1概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。
顺序表一般分为:
静态顺序表:使用定长数组储存元素。
//静态顺序表
#define N 100
struct SeqList
{int a[N];//定长数组int size;//有效数据的个数
};

缺点:不是很灵活
动态顺序表:使用动态开辟的数组储存。

2.2接口实现
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空
间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间
大小,所以下面我们实现动态顺序表。
所谓动态其实指的这个结构体里的指针是动态内存开辟来的,是可变的,用的时候动态开辟,不够的话继续开辟,程序结束的时候释放。
2.3动态顺序表的创建
typedef int SLDatatype;//将int重命名为SLDatatype
typedef struct SeqList
{SLDatatype* a;//指向动态开辟的数组SLDatatype capacity;//容量SLDatatype size;//有效数据的个数}SL;//将结构体SeqList重命名为SL
2.3动态顺序表的初始化
2.3.1传值初始化
//传值初始化
void SLInit(SL s)
{s.a = NULL;s.size = 0;s.capacity = 0;
}
函数那个章节我们学过形参只是实参的临时拷贝,并没有实际作用,生命周期短,出了函数的作用域就会销毁,我们不考虑这种初始化方式。
2.3.2传址初始化
//传址初始化
void SLInit(SL* ps)
{ps->a = 0;ps->capacity = 0;ps->size = 0;
}
void SLInit(SL* ps)
{ps->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4);//开辟了4个字节的空间if (ps->a == NULL){perror("malloc failed");exit(-1);}ps->capacity = 4;//开辟了空间就要给容量赋值ps->size = 0;
}
上面两种初始化方式都可以给予结构体成员变量赋值,但是我们使用第二种,因为第二种为我们开辟了空间。
2.4动态顺序表的清空
void SLDestr(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = 0;//内存释放,容量清零ps->size = 0;//内存释放,有效数据清零
}
2.5动态顺序表的扩容
void SLCheckcapacity(SL* ps)
{if (ps->size == ps->capacity){SLDatatype* tmp = (SLDatatype*)realloc(ps->a, ps->capacity * 2 *( sizeof(SLDatatype)));//扩容尾原来的倍数if (tmp == NULL)//判断是否扩容失败{perror("realloc failed");exit(-1);}ps->a = tmp;ps->capacity *= 2;//扩容后修改原来的容量}
}
这就是所谓的动态,当我们空间不够时,就需要开辟新的空间,使用realloc函数要注意是否开辟成功,定义一个中间指针,当开辟成功时将这个指针赋值给动态数组中的指针。
2.6动态顺序表内容的打印
void SLprint(SL* ps)
{int i = 0;for (i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}
size为有效数据个数,使用循环打印其中的有效数据。
三、动态顺序表的使用
3.1尾插尾删
3.1.1尾插
void SLPushBack(SL* ps, SLDatatype x)
{SLCheckcapacity(ps);//检查空间是否足够插入ps->a[ps->size] = x;//赋值ps->size++;//插入一个有效数据,有效数据个数加一
}
首先一定要检查规矩是否足够,根据上面开辟的空间,容量为4,有效数据为size为0,所以从第一个空间开始插入数据。
3.1.2尾删
//尾删
void SLPopBack(SL* ps)
{assert(ps->size > 0);//判断是否会造成越界if (ps->size == 0){return;}ps->size--;//删除一个数据,有效数据个数减一
}
插入数据后size的大小也会变化,数组中最后一个数字的下标刚好和size的大小一样我们只需要将size减1就行。
3.2头插头删
3.2.1头插
void SLPushFront(SL* ps, SLDatatype x)
{SLCheckcapacity(ps);//检查空间是否足够int end = ps->size;while (end > 0){ps->a[end] = ps->a[end - 1];//将前一个数据后移动end--;}ps->a[0] = x;//将x赋给初始位置ps->size++;//加入一个数字,有效数据个数加1
}
老规矩一定要检查空间是否足够,头部插入数据我们只需要将原来的数据往后移动一格就将第一格的位置空出来,再将数值插入就行,插入一个数据,有效数据加1即可。
3.2.2头删
void SLPopFront(SL* ps)
{assert(ps->size > 0);//防止越界访问if (ps->size==0){return;}int begin = 0;while (begin < ps->size){ps->a[begin] = ps->a[begin+1];//将后一个数据往前移动begin++;}ps->size--;//减少一个数字,有效数据减1
}
这里的删除并不是真正意义上的删除,我们只需要将原来的数据往前移动一位使后一位的数据覆盖在前一位,这就做到了删除,顺便再将有效数据减1就行。
3.3在pos位置插入x
void SLInsert(SL* ps, int pos, int x)
{assert(pos >= 0 && pos <= ps->size);//防止越界访问SLCheckcapacity(ps);int end = ps->size;while (end >=pos){ps->a[end] = ps->a[end-1];//和头插的思想差不多,将数据后移end--;}ps->a[pos] = x;//将x赋值给pos位置ps->size++;//有效数据加1
}
我们可以这样理解:将pos看成初始位置,是不是就转化为头插了?按照头插的思想就可以完成在pos位置上插入x。
3.4删除pos位置的值
void SLErase(SL* ps, int pos)
{assert(pos >= 0 && pos <= ps->size);//防止越界访问SLCheckcapacity(ps);int begin = pos;while (begin < ps->size){ps->a[begin] = ps->a[begin + 1];//和头删的思想差不多,将数据前移begin++;}ps->size--;//有效数据减1
}
我们会发现3.4和3.5不仅可以做到某个位置值的插入和删除,也可以做到尾插尾删和头插头删。
3.5修改某个位置的值
void SLModify(SL* ps, SLDatatype pos, SLDatatype x)
{assert(pos >= 0 && pos < ps->size);//防止越界ps->a[pos] = x;
}
这样修改某个位置的值看起来是挺麻烦,但是是为了安全考虑。
四、完整代码
#define _CRT_SECURE_NO_WARNINGS 67
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
//静态顺序表
//#define N 100
//struct SeqList
//{
// int a[N];//定长数组
// int size;//有效数据的个数
//};//动态顺序表//创建
typedef int SLDatatype;
typedef struct SeqList
{SLDatatype* a;//指向动态开辟的数组SLDatatype capacity;//容量SLDatatype size;//有效数据的个数}SL;
//传值初始化
//void SLInit(SL s)
//{
// s.a = NULL;
// s.size = 0;
// s.capacity = 0;
//}
//传址初始化
//void SLInit(SL* ps)
//{
// ps->a = 0;
// ps->capacity = 0;
// ps->size = 0;
//}
void SLInit(SL* ps)
{ps->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4);//开辟了4个字节的空间if (ps->a == NULL){perror("malloc failed");exit(-1);}ps->capacity = 4;ps->size = 0;
}
//清空
void SLDestr(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = 0;ps->size = 0;
}
//打印
void SLprint(SL* ps)
{int i = 0;for (i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}
//检查容量
void SLCheckcapacity(SL* ps)
{if (ps->size == ps->capacity){SLDatatype* tmp = (SLDatatype*)realloc(ps->a, ps->capacity * 2 *( sizeof(SLDatatype)));//扩容尾原来的倍数if (tmp == NULL){perror("realloc failed");exit(-1);}ps->a = tmp;ps->capacity *= 2;}
}
//尾插
void SLPushBack(SL* ps, SLDatatype x)
{SLCheckcapacity(ps);ps->a[ps->size] = x;ps->size++;
}
//尾删
void SLPopBack(SL* ps)
{assert(ps->size > 0);if (ps->size == 0){return;}ps->size--;
}
//头插
void SLPushFront(SL* ps, SLDatatype x)
{SLCheckcapacity(ps);int end = ps->size;while (end > 0){ps->a[end] = ps->a[end - 1];end--;}ps->a[0] = x;ps->size++;
}
//头删
void SLPopFront(SL* ps)
{assert(ps->size > 0);if (ps->size==0){return;}int begin = 0;while (begin < ps->size){ps->a[begin] = ps->a[begin+1];begin++;}ps->size--;
}
//在pos位置插入x
void SLInsert(SL* ps, int pos, int x)
{assert(pos >= 0 && pos <= ps->size);SLCheckcapacity(ps);int end = ps->size;while (end >=pos){ps->a[end] = ps->a[end-1];end--;}ps->a[pos] = x;ps->size++;
}
//删除pos位置的值
void SLErase(SL* ps, int pos)
{assert(pos >= 0 && pos <= ps->size);SLCheckcapacity(ps);int begin = pos;while (begin < ps->size){ps->a[begin] = ps->a[begin + 1];begin++;}ps->size--;
}
int SLFind(SL* ps, int x)
{int i = 0;for (i = 0; i < ps->size; i++){if (ps->a[i] == x)return i;}return -1;
}void SLModify(SL* ps, SLDatatype pos, SLDatatype x)
{assert(pos >= 0 && pos < ps->size);ps->a[pos] = x;
}
int main()
{SL s1;//传值初始化//SLInit(s1);//传址初始化SLInit(&s1);//尾插SLPushBack(&s1, 1);SLPushBack(&s1, 2);SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushBack(&s1, 5);SLPushBack(&s1, 6);SLPushBack(&s1, 7);//尾插测试printf("尾插:\n");SLprint(&s1);//尾删SLPopBack(&s1);//尾删测试printf("尾删:\n");SLprint(&s1);//头插SLPushFront(&s1,10);//头插测试printf("头插:\n");SLprint(&s1);//头删 SLPopFront(&s1);//头删测试printf("头删:\n");SLprint(&s1);//在pos位置插入xSLInsert(&s1, 0, 100);//pos插入x测试printf("pos位置插入x\n");SLprint(&s1);//删除pos位置的值SLErase(&s1, 0);//测试printf("删除pos位置的值\n");SLprint(&s1);//改SLModify(&s1, 2, 1);printf("修改某个位置上的值:\n");//SLprint(&s1);//清空SLDestr(&s1);return 0;
}

相关文章:
详解初阶数据结构之顺序表(SeqList)——单文件文件实现SeqList的增删查改
目录 一、线性表 二、顺序表 2.1概念及结构 2.2接口实现 2.3动态顺序表的创建 2.3动态顺序表的初始化 2.3.1传值初始化 2.3.2传址初始化 2.4动态顺序表的清空 2.5动态顺序表的扩容 2.6动态顺序表内容的打印 三、动态顺序表的使用 3.1尾插尾删 3.1.1尾插 3.1.2尾删…...
JavaScript中的深拷贝和浅拷贝
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 浅拷贝(Shallow Copy):⭐深拷贝(Deep Copy):⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带…...
树形结构的节点作为查询参数业务
1、业务描述 有一个树结构,存在一个唯一的code和一个父节点的pcode,要求前端传入任意层的code匹配这个code对应的所有子节点对应的数据。 2、解决思路 因为无法判定传入的code到底在那层,so 直接递归调用查询判断,如果有子节点就…...
sql:SQL优化知识点记录(十二)
(1)读锁案例讲解 加读锁和写锁 查看是否上锁:In_use:变成了1 读写锁对我们数据产生哪些影响: 读锁:是共享锁,其他线程可以查看: 加了读锁:session1不能修改自己…...
一.使用qt creator 设计显示GUI
一.安装qt creator 二.创建项目 文件-》新建项目 三.使用设计 可以直接使用鼠标拖拽 四.转换为py文件 # from123.py 为导出 py文件的文件名 form.ui 为 qt creator创造的 ui 文件 pyuic5 -o x:\xxx\from123.py form.ui五.显示GUI from PyQt5.QtWidgets import * fr…...
sql:SQL优化知识点记录(八)
(1)索引面试题分析 所谓索引:就是排好序的快速查找数据结构,排序家查找是索引的两个用途 select * 在where使用到了索引,当select * 有模糊查询%在左边索引会失效 当select * where后面索引的顺序发生变化࿰…...
java笔试题,寻找多出来的元素
题目:有两个数组a和b,其中b有一个元素是a没有的,其他元素都相同,请找出b中这个多余的元素。 1 public class Test02 { 2 3 public static void main(String[] args) { 4 int[] a {11, 34, 9, -4, 100, 98}; 5 int[] b {34…...
docker笔记3 Docker常规安装
1.安装tomcat docker hub上面查找tomcat镜像 docker search tomcat 从docker hub上拉取tomcat镜像到本地 docker pull tomcat docker images查看是否有拉取到的tomcat 使用tomcat镜像创建容器实例(也叫运行镜像) docker run -it -p 8080:8080 tomcat -p 小写,主…...
阻止 NTLM后无法登录远程桌面的原因
阻止 NTLM(NT LAN Manager) 攻击设置二 之前郑州景安的服务器被攻击,没过几天阿里云的也被攻击,且都是 NTLM 攻击。 Operating System: Windows Server 2008(R2) Enterprise Service Pack 1 64bit 一、winr 输入 gpedit.msc 二、依次进入:…...
Docker网络功能
基本网络功能 Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。使用docker network子命令来管理Docker网络。 外部访问容器可通过端口映射实现,启动容器时使用-p参数指定映射关系。-p可多次使用来绑定多个端口。使用docker port命令查看当前映射的端…...
如何入门 AI----如何确定学习目标
当确定学习人工智能(AI)的目标时,可以考虑以下具体的步骤: 兴趣和好奇心: 首先,问问自己,您对哪些 AI 领域感兴趣?是机器学习、自然语言处理、计算机视觉,还是其他领域&a…...
ABAP中加前导零和去前导零方法
文章目录 1 Introduction2 Method 1 Introduction In the sap there are two method for leading zero. We can use function or use the below the method . 2 Method SELECT * INTO TABLE DATA(IT_ITEM)FROM MARA .LOOP AT IT_ITEM ASSIGNING FIELD-SYMBOL(<FS_DATA&g…...
聊聊ShardingSphere是怎么进行sql重写的
序 本文主要研究一下ShardingSphere进行sql重写的原理 prepareStatement org/apache/shardingsphere/driver/jdbc/core/connection/ShardingSphereConnection.java public final class ShardingSphereConnection extends AbstractConnectionAdapter {Overridepublic Prepar…...
软件设计模式系列之二——抽象工厂模式
1 抽象工厂模式的定义 抽象工厂模式是一种创建型设计模式,它提供了一种创建一组相关或相互依赖对象的方式,而无需指定它们的具体类。该模式以一组抽象接口为核心,包括抽象工厂接口和一组抽象产品接口,每个具体工厂类负责创建特定…...
P2719 搞笑世界杯 (期望dp
#include <bits/stdc.h> using namespace std; using VI vector<int>;double dp[2000][2000]; int n; //求dp[2][0] //dp[0][2] //期望dp要从终末态,向起始态转移 //dp[a][b] - > dp[a][b-1] or dp[a-1][b] //dp[a][b] 1/2 * dp[a][b1] 1/2 * dp…...
spring cloud新版本使用loadbalancer替代Ribbon
Nacos 2021 不再集成 Ribbon,建议使用spring cloud loadbalancer 引入 一、简单使用 引入依赖spring cloud loadbalancer <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer<…...
【Git-Exception】Git报错:fatal: unable to auto-detect email address
报错信息: *** Please tell me who you are. Run git config --global user.email “youexample.com” git config –global user.name “Your Name” to set your account’s default identity. Omit --global to set the identity only in this repository. fatal…...
JVM性能优化 —— 类加载器,手动实现类的热加载
一、类加载的机制的层次结构 每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Java代码经转换后的虚拟机指令,当需要使用某个类时&#…...
SSH连接MobaXterm
IT常用软件的安装 ssh连接MobaXterm详细使用教程 数据库Navicat安装:https://www.jianshu.com/p/2494e02caf63 java SE安装 https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html windows安装pip https://www.cnblogs.com/NanShan2016/…...
本地虚机Jumpserver使用域名访问报错 使用IP+端口没有错误
背景: 我在本地Windows VMware 15的环境中部署了CentOS7.5,下载jumpserver-offline-installer-v2.28.1-amd64-138.tar.gz并安装部署。 需求: 1、能使用http:ip访问堡垒机。达成; 2、能使用http:域名访问堡垒机。达成ÿ…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
