当前位置: 首页 > news >正文

从无到有开始创建动态顺序表——C语言实现

顺序表的概念

       顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口。在物理结构和逻辑结构都是连续的,物理结构是指顺序表在计算机内存的存储方式,逻辑结构是我们思考的形式,顺序表和数组是类似的,都是使用了连续的空间进行数据的保存,由于是连续的空间,所以逻辑结构当然也可以像数组一样去思考,所以说逻辑结构也是连续的。

静态顺序表

       静态顺序表是指顺序表的空间大小一开始就是给定的,这也就有一个弊端,如果空间给大了,就会造成空间浪费,也就不经济了,如果空间给小了,就有可能出现空间不够,造成数据丢失。

动态顺序表

       动态顺序表是指空间大小是可以动态的变化的,随着数据的增多,如果空间不够就会自动扩容,所以动态顺序表相比静态的顺序表更加灵活,这里我会以动态的顺序表进行讲解~~

顺序表的实现

       顺序表的实现主要分为初始化,插入数据,删除数据,查找数据以及销毁。这里我们需要三个文件,一个是顺序表的头文件(SeqList.h),一个是顺序表的实现文件(SeqList.c),最后一个就是我们的测试文件(test.c),加测试文件是用来测试代码有没有写错,这也还是一个程序员的必备技能。

定义顺序表的结构

       由于是动态的顺序表,我们就需要一个指针变量,一个变量(size)来记录当前存储了多少空间,还有一个变量来记录当前的容量大小(capacity)来判断是否需要扩容。
定义如下:

typedef int SLDataType;
#define MAX_CAPACITY 4typedef struct SeqList
{SLDataType* data;int size;int capacity;
}SL;

稍微解释一下,为什么使用SLDataType ,为了方便后期修改数据类型,这次使用int,万一下次使用char、double…
MAX_CAPACITY 是来定义初始容量是多少,下面我们会用到。

初始化与销毁

初始化很简单,就是把指针置空,把容量和size置为0.

void SLInit(SL* ps)//顺序表初始化
{ps->data = NULL;ps->size = ps->capacity = 0;
}

销毁:需要我们释放动态内存开辟的空间。

void SLDestory(SL* ps)//顺序表销毁
{assert(ps);free(ps->data);ps->data = NULL;ps->size = ps->capacity = 0;
}

插入数据

       
这里的插入数据分为三种方式的插入,头插,尾插,指定位置插入。

//插入
void SLPushBack(SL* ps, SLDataType x);//尾插
void SLPushFront(SL* ps, SLDataType x);//头插
void SLPushPos(SL* ps, int pos, SLDataType x);//指定位置插入

扩容

在插入数据之前我们需要对空间进行检查,看看是否需要扩容,由于插入函数有三个,那就意味着要写三次扩容,为了方便,我们就再创建一个函数来检查是否需要扩容。

void SLCheckCapacity(SL* ps)
{assert(ps);if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? MAX_CAPACITY : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->data, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail");exit(1);}ps->data = tmp;ps->capacity = newcapacity;}
}

这里我们要注意了:什么时候判断扩容?扩容条件就需要当前的数据量和容量是相等的情况下进行,这里我们建议以2倍或3倍来进行扩容(不信的小伙伴可以自己百度一下,这里涉及数学知识)
但是,当容量为空的时候,无论你是几倍,最后都是0,所以我们可以先判断一下容量是否为0,如果为0,就赋值为我们上面定义的初始容量,否则就是正常的2倍或3倍来扩容。
使用什么动态开辟函数,这里使用realloc,因为realloc不仅具有和malloc函数一样的开辟功能(就是传入的指针为NULL时,就可以看成malloc一样自动开辟一块内存空间,不了解的可以翻阅我的动态内存函数详解那一篇博客),而且realloc还具有扩容的功能,所以推荐使用realloc进行动态开辟。
由于realloc 可能会开辟失败,返回NULL,所以我们用一个变量来接收,直接接收的话,会导致无法找回之前的空间,导致内存泄漏。

尾插

尾插就是从后面开始插入数据,这个很简单,但是要保证传来的指针不为NULL,并且检查是否需要扩容。

void SLPushBack(SL* ps, SLDataType x)//尾插
{assert(ps);SLCheckCapacity(ps);ps->data[ps->size++] = x;
}

头插

头插时从第一个空间开始插入数据,所以要先把后面的数据向后移动,避免数据丢失。

void SLPushFront(SL* ps, SLDataType x)//头插
{assert(ps);SLCheckCapacity(ps);int i = 0;for (i = ps->size; i > 0; i--){ps->data[i] = ps->data[i - 1];}ps->data[0] = x;ps->size++;
}

指定位置插入

我们需要找到指定的位置,从这里开始后面的数据都需要往后移动,然后腾出来位置留给新来的数据,这是对中间插入的考虑,我们还需要考虑,如果传入的位置正好是头部或者是尾部的时候,是不是也是这样,很显然,一个循环确实能保证这两种情况。

最后我们要注意如果传来的pos是一个负数或者超过尾部的时候,我们是不允许插入的,这里我们可以判断一下,或者直接警告。

void SLPushPos(SL* ps, int pos, SLDataType x)//指定位置插入
{assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);int i = 0;for (i = ps->size; i > pos; i--){ps->data[i] = ps->data[i - 1];}ps->data[pos] = x;ps->size++;
}

删除数据

       
这里的删除数据也分为三种方式的删除,头删,尾删,指定位置删除。

在删除数据的时候,我们要保证有数据可以删除,否则size就会变成负数,不利于后续的插入操作,这里我们判断一下就可以了。

尾删

void SLPopBack(SL* ps)//尾删
{assert(ps);assert(ps->size);ps->size--;
}

头删

这个很简单就是把数据往前移动,最后size–就可以了。

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

指定位置删除

和头删类似,把数据往前移动,也要注意pos 的值

void SLPopPos(SL* ps, int pos)//指定位置删除
{assert(ps);assert(ps->size);assert(pos >= 0 && pos < ps->size);int i = 0;for (i = pos; i < ps->size - 1; i++){ps->data[i] = ps->data[i + 1];}ps->size--;
}

查找

顾名思义就是查找一个数据的小标:

int SLFind(SL* ps, SLDataType x)
{assert(ps);int i = 0;for (i = 0; i < ps->size; i++){if (ps->data[i] == x){return i;}}return -1;
}

打印

为了方便测试,我们可以写一个打印函数。

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

测试和封装

我们每写完一个函数就要进行调试
我们可以写一些测试函数,来进行测试,要注意测试的代码尽量包含边界情况和中间情况(尤其是插入和删除函数的测试)
就类似下面的测试代码:

#include"SeqList.h"//void Test1()
//{
//	SL sl;
//	SLInit(&sl);
//	SLPushBack(&sl,1);
//	SLPushBack(&sl,2);
//	SLPushBack(&sl,3);
//	SLPushFront(&sl, 5);
//	SLPushFront(&sl, 10);
//	SLPushPos(&sl, 2, 50);
//	SLPrint(sl);
//	SLPushPos(&sl, 4, 100);
//	SLPrint(sl);
//
//	SLDestory(&sl);
//}
//
//void Test2()
//{
//	SL sl;
//	SLInit(&sl);
//	SLPushBack(&sl, 1);
//	SLPushBack(&sl, 2);
//	SLPushBack(&sl, 3);
//
//	SLPopPos(&sl,1);
//	SLPrint(sl);
//
//}void Test3()
{SL sl;SLInit(&sl);SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPrint(sl);SLPushFront(&sl, 10);SLPushFront(&sl, 20);SLPushFront(&sl, 30);SLPrint(sl);SLPushPos(&sl, 1, 200);SLPrint(sl);SLPushPos(&sl, sl.size ,100);SLPrint(sl);SLPushPos(&sl, 0, 5000);SLPrint(sl);SLPopBack(&sl);SLPrint(sl);SLPopFront(&sl);SLPrint(sl);SLPopPos(&sl, 0);SLPrint(sl);SLPopPos(&sl, 2);SLPrint(sl);SLPopPos(&sl, sl.size-1);SLPrint(sl);printf("%d\n",SLFind(&sl, 1));SLDestory(&sl);
}int main()
{//Test1();//Test2();Test3();return 0;
}

接着我们需要注意把函数的实现放在SeqList.c文件里,把结构体、函数声明、define、typedef等放在SeqList,h里。完成函数的封装。

相关文章:

从无到有开始创建动态顺序表——C语言实现

顺序表的概念 顺序表的底层结构是数组&#xff0c;对数组的封装&#xff0c;实现了常用的增删改查等接口。在物理结构和逻辑结构都是连续的&#xff0c;物理结构是指顺序表在计算机内存的存储方式&#xff0c;逻辑结构是我们思考的形式&#xff0c;顺序表和数组是类似的&#x…...

Unix 网络编程, Socket 以及bind(), listen(), accept(), connect(), read()write()五大函数简介

Unix网络编程是针对类Unix操作系统&#xff08;包括Linux、BSD以及其他遵循POSIX标准的操作系统&#xff09;进行网络通信开发的技术领域。网络编程涉及创建和管理网络连接、交换数据以及处理不同层次网络协议栈上的各种网络事件。在Unix环境中&#xff0c;网络编程通常涉及到以…...

【附下载】2024全行业数字化转型企业建设解决方案PPT合集

精品推荐&#xff0c;2024全行业数字化转型企业建设解决方案PPT合集&#xff0c;精品PPT源格式共21份。 以下是资料目录&#xff0c;如需下载&#xff0c;请前往星球获取&#xff1a; 1.制造业数字化转型解决方案及应用.pptx 2.医院数字化网络解决方案.pptx 3.食品饮料工厂数字…...

【QT+QGIS跨平台编译】056:【pdal_lepcc+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal_lepcc介绍二、pdal下载三、文件分析四、pro文件五、编译实践一、pdal_lepcc介绍 pdal_lepcc 是 PDAL(Point Data Abstraction Library)的一个插件,用于点云数据的压缩。它基于 EPCC(Entwine Point Cloud Compression)算法,提供了对点…...

蓝桥集训之斐波那契数列

蓝桥集训之斐波那契数列 核心思想&#xff1a;矩阵乘法 将原本O(n)的递推算法优化为O(log2n) 构造1x2矩阵f和2x2矩阵a 发现f(n1) f(n) * a 则f(n1) f(1) * an可以用快速幂优化 #include <iostream>#include <cstring>#include <algorithm>using na…...

程序员的工资是多少,和曹操有莫大的关系

曹操是谁大家都知道了吧&#xff0c;他是三国时期的一个有名的大老板&#xff0c;谁知道曹操的工资是多少呢&#xff1f;这个其实也不好说&#xff0c;有时候曹操赚很多的钱&#xff0c;有时候也亏血本&#xff0c;甚至连脑袋都差点掉了。创业不容易啊&#xff0c;曹老板也是如…...

使用Element Plus

1. 官网安装 安装 | Element Plus (gitee.io) 安装&#xff1a; npm install element-plus --save 在main.ts中全局注册ElementPlus并使用 //加入element-plus import ElementPlus from element-plus; //加入element-plus样式 import element-plus/dist/index.css; import…...

单例(Singleton)设计模式总结

1. 设计模式概述&#xff1a; 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。 就像是经典的棋谱&#xff0c;不同的棋局&#xff0c;我们用不同的棋谱。"套路"经典的设计模式一共有…...

LeetCode每日一题之专题一:双指针 ——快乐数

快乐数OJ链接&#xff1a;202. 快乐数 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 题目分析: 为了房便叙述&#xff0c;将「对于⼀个正整数&#xff0c;每⼀次将该数替换为它每个位置上的数字的平方和」这⼀个 操作记为 x 操作&#xff1b; 题目告诉我们&#…...

Docker Desktop 不支持 host 网络模式

先把这个结论的放在前面&#xff0c;直接访问链接就能看到官方文档中已经明确说了不支持。 参考链接&#xff1a;docker desktop for windows 不支持 host 网络模式 以前对于 docker 的网络模式&#xff0c;一直只是了解&#xff0c;没有亲自尝试过。结果今天在尝试 docker 的 …...

Linux网络编程二(TCP图解三次握手及四次挥手、TCP滑动窗口、MSS、TCP状态转换、多进程/多线程服务器实现)

文章目录 1、TCP三次握手(1) 第一次握手(2) 第二次握手(3) 第三次握手 2、TCP四次挥手(1) 一次挥手(2) 二次挥手(3) 三次挥手(4) 四次挥手 3、TCP滑动窗口4、TCP状态时序图5、多进程并发服务器6、多线程并发服务器 1、TCP三次握手 TCP三次握手(TCP three-way handshake)是TCP协…...

【云原生篇】K8S之Job 和 CronJob

在 Kubernetes (K8s) 中&#xff0c;Job 和 CronJob 是两种管理批处理任务的资源对象&#xff0c;它们用于控制短暂的一次性任务&#xff08;Job&#xff09;或定时执行的周期性任务&#xff08;CronJob&#xff09;。 Job 概念 Job 负责运行一个或多个 Pod&#xff0c;并确…...

PHP8.3-ZTS版本安装流程以及添加扩展

下载php-8.3.x.tar.gz至服务器并解压 [rootapisix-test php-8.3.4]# wget https://www.php.net/distributions/php-8.3.4.tar.gz进入目录执行编译命令&#xff0c;必须要带 --enable-zts 才能激活zts功能 [rootapisix-test php-8.3.4]# ./configure --prefix/usr/local/p…...

RabbitMQ系统监控、问题排查和性能优化实践

一、系统监控&#xff1a;RabbitMQ的各项性能指标及监控 Message Rates&#xff1a;消息率包含了publish&#xff0c;deliver/get&#xff0c;ack等方面的数据&#xff0c;反映了消息在系统中流转的情况。Queue Length&#xff1a;队列长度反映了系统当前的负载情况。如果队列…...

【华为OD机试】根据IP查找城市(贪心算法—JavaPythonC++JS实现)

本文收录于专栏:算法之翼 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目二.解题思路三.题解代码Python题解代码JAVA题解代码C/C++题解代码JS题解代码四.代码讲解(Ja…...

css:阴影效果box-shadow

属性 box-shadow 属性值由四个参数组成&#xff1a; 水平偏移量&#xff1a;表示阴影相对于元素的水平位置。垂直偏移量&#xff1a;表示阴影相对于元素的垂直位置。模糊度&#xff1a;表示阴影的模糊程度。颜色&#xff1a;表示阴影的颜色 示例 单个box-shadow 0px -2px 6p…...

Scala第十九章节(Actor的相关概述、Actor发送和接收消息以及WordCount案例)

Scala第十九章节 章节目标 了解Actor的相关概述掌握Actor发送和接收消息掌握WordCount案例 1. Actor介绍 Scala中的Actor并发编程模型可以用来开发比Java线程效率更高的并发程序。我们学习Scala Actor的目的主要是为后续学习Akka做准备。 1.1 Java并发编程的问题 在Java并…...

蓝桥杯杯赛之深度优先搜索优化《1.分成互质组》 《 2.小猫爬山》【dfs】【深度搜索剪枝优化】【搜索顺序】

文章目录 思想例题1. 分成互质组题目链接题目描述【解法一】【解法二】 2. 小猫爬山题目链接题目描述输入样例&#xff1a;输出样例&#xff1a;【思路】【WA代码】【AC代码】 思想 本质为两种搜索顺序&#xff1a; 枚举当前元素可以放入哪一组枚举每一组可以放入哪些元素 操…...

软件设计原则:依赖倒置

定义 依赖倒置原则&#xff08;Dependency Inversion Principle, DIP&#xff09;是面向对象设计原则之一&#xff0c;其核心是高层模块&#xff08;如业务逻辑&#xff09;不应当依赖于低层模块&#xff08;如具体的数据访问或设备控制实现&#xff09;&#xff0c;而是双方都…...

03-自媒体文章发布

自媒体文章发布 1)自媒体前后端搭建 1.1)后台搭建 ①&#xff1a;资料中找到heima-leadnews-wemedia.zip解压 拷贝到heima-leadnews-service工程下&#xff0c;并指定子模块 执行leadnews-wemedia.sql脚本 添加对应的nacos配置 spring:datasource:driver-class-name: com…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Pydantic + Function Calling的结合

1、Pydantic Pydantic 是一个 Python 库&#xff0c;用于数据验证和设置管理&#xff0c;通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发&#xff08;如 FastAPI&#xff09;、配置管理和数据解析&#xff0c;核心功能包括&#xff1a; 数据验证&#xff1a;通过…...