【数据结构手札】顺序表实战指南(二):结构体构建 | 初始化 | 打印 | 销毁

【数据结构手札】顺序表实战指南(二):结构体构建 | 初始化 | 打印 | 销毁
在这里插入图片描述


🌈个人主页:聆风吟
🔥系列专栏:数据结构手札
🔖少年有梦不应止于心动,更要付诸行动。


文章目录

📚专栏订阅推荐

专栏名称专栏简介
C++藏宝阁本专栏聚焦学习阶段核心知识点,深耕基础与实战,干货笔记持续更新,和大家共学共进,夯实编程功底。
数据结构手札本专栏主要是我的数据结构入门学习手札,记录个人从基础到进阶的学习总结。
数据结构手札・刷题篇本专栏是《数据结构手札》配套习题讲解,通过练习相关题目加深对算法理解。

📋前言 - 顺序表文章合集

-【顺序表(一):线性表定义 | 顺序表定义】

-【顺序表(二):初始化 | 打印 | 销毁】

-【顺序表(三):扩容 | 尾插 | 尾删】

-【顺序表(四):头插 | 头删】

-【顺序表(五):查找 | 任意位置增删】


一. ⛳️顺序表:重点回顾

1.1 🔔顺序表的定义

顺序表(Sequential List):用一段物理地址连续的存储单元依次存储数据元素的线性结构。一般情况下采用数组存储。在数组上完成数据的增删查改。

在这里插入图片描述



1.2 🔔顺序表的分类

顺序表一般可以分为:静态顺序表动态顺序表

1.2.1 👻静态顺序表

静态顺序表:指存储空间是固定的并且在程序运行前就已经确定大小的顺序表。它通常使用数组来实现,即通过定义一个固定长度的数组来存储数据元素。

静态顺序表的结构定义:

//静态顺序表结构定义#defineMAXSIZE7//存储单元初始分配量typedefint SLDataType;//类型重命名,便于统一修改元素类型typedefstructSeqList{ SLDataType data[MAXSIZE];//定长数组int size;//当前有效数据的个数}SeqList;

我们可以发现描述静态顺序表需要三个属性:

  • 存储空间的起始位置:数组data,他的存储位置就是存储空间的存储位置;
  • 线性表的最大存储容量:数组长MAXSIZE
  • 线性表的当前位置:size
在这里插入图片描述



1.2.2 👻动态顺序表

动态顺序表:通过动态分配内存空间,实现随着数据量的增加而不断扩容的效果。它的结构类似于一个数组,数据元素的存储是连续的,支持随机访问和顺序访问。

动态顺序表的结构定义:

//动态顺序表结构定义typedefint SLDataType;//类型重命名,便于统一修改元素类型typedefstructSeqList{ SLDataType* a;//指向动态开辟的数组int size;//当前有效数据的个数int capacity;//当前分配的总容量}SL;

我们可以发现描述动态顺序表也需要三个属性:

  • 存储空间的起始位置:指针a,他里面存储的地址就是存储空间的地址;
  • 线性表当前最大存储容量:capacity,可以通过动态分配的方式进行扩容;
  • 线性表的当前位置:size
在这里插入图片描述

二. ⛳️顺序表的基本操作实现

通过上期学习,我们已经了解了动态顺序表可以使程序更加高效和灵活,可以根据实际数据量动态地调整表的大小,避免在创建静态顺序表时浪费内存空间或者当数据量超出静态顺序表容量时造成数据丢失或程序崩溃等问题。因此,本文将采用动态顺序表结合图文去实现顺序表的一些基本操作。

2.1 🔔动态顺序表结构体构建

//动态顺序表#defineSLCAPACITY4typedefint SLDataType;typedefstructSeqList{ SLDataType* a;//指向动态开辟的数组int size;//有效数据的个数int capacity;//记录容量的空间大小}SL;

代码深剖:

  • 结构体中 a 指向的数组类型是我们重定义的SLDataType,这样当我们想创建其它类型的顺序表时只需要对 typedef 后面的数据类型int进行需改即可;
  • size是用来计数的,统计当前顺序表一共有多少个有效元素;
  • capacity是用来表示当前顺序表的容量,当size==capacity时说明当前顺序表已经“装满了”,需要扩容;
  • 定义标识符SLCAPACITY作为宏常量,用于指定顺序表初始化时的初始容量。便于将初始容量的值 “集中管理”,后续如果需要调整顺序表的初始容量(比如想把默认 4 个空间改成 8 个),无需在初始化函数的代码里逐个修改数值,只需修改INIT_CAPACITY的定义即可,既减少了代码出错的概率,也让程序的可维护性大大提升。

2.2 🔔初始化顺序表

//初始化顺序表voidSLInit(SL* ps){assert(ps);//使用malloc开辟空间 ps->a =(SLDataType*)malloc(sizeof(SLDataType)* SLCAPACITY);//判断空间是否开辟成功if(NULL== ps->a){//打印错误原因(比如 “malloc failed: Out of memory”),方便定位问题;perror("malloc failed");//终止程序并返回非 0 状态码(约定俗成表示程序异常退出),避免后续无效操作。exit(-1);}//初始化顺序表的有效元素个数为 0。 ps->size =0;//记录顺序表当前的最大容量。 ps->capacity = SLCAPACITY;}

代码深剖:

  • assert(ps);主要用于校验传入的顺序表指针是否有效(非空)。assert是断言宏,若psNULL(空指针),程序会直接终止并提示断言失败。因为后续所有操作都基于ps指向的顺序表结构体,如果传入空指针,操作ps->aps->size等会导致程序崩溃,这是防御性编程的核心手段,提前规避空指针访问的致命错误。(后文在出现就不多做叙述了)。
  • 使用malloc开辟空间,一定要进行判断是否开辟成功。因为malloc申请内存失败时(比如系统剩余内存不足)会返回NULL,若直接使用NULL指针操作数组,会触发 “段错误” 导致程序崩溃;

时间复杂度:

该程序没有循环,根据大O阶的推导方法很容易得出:初始化顺序表的时间复杂度为O(1)

2.3 🔔销毁顺序表

//销毁顺序表voidSLDestroy(SL* ps){assert(ps);//释放顺序表底层数组占用的动态内存。free(ps->a);//将指针置空,避免 “野指针” 问题。 ps->a =NULL;//重置顺序表的状态变量,让其回归 “初始无效状态”。 ps->size = ps->capacity =0;}

代码深剖:
为什么必须调用销毁函数?因为我们实现的是动态顺序表,其底层数组a指向的内存是通过malloc向操作系统 “临时申请” 的 —— 系统不会自动回收这块内存,如果使用后忘记释放,会造成内存泄漏:轻则持续占用系统资源,导致程序运行越久越卡顿;重则内存被耗尽,引发程序崩溃甚至系统异常。
时间复杂度:

该程序没有循环,根据大O阶的推导方法很容易得出:销毁顺序表的时间复杂度为O(1)

2.4 🔔打印顺序表

//打印顺序表voidSLPrint(SL* ps){assert(ps);for(int i =0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");}

代码深剖:
打印顺序表就是进行简单的遍历循环,此处不多做叙述。

时间复杂度:

该程序有单层循环,根据大O阶的推导方法很容易得出:打印顺序表的时间复杂度为O(n)

三. ⛳️顺序表的源代码

3.1 🔔SeqList.h 顺序表的函数声明

#include<stdio.h>#include<stdlib.h>#include<assert.h>//动态顺序表#defineSLCAPACITY4typedefint SLDataType;typedefstructSeqList{ SLDataType* a;//指向动态开辟的数组int size;//有效数据的个数int capacity;//记录容量的空间大小}SL;//初始化voidSLInit(SL* ps);//销毁顺序表voidSLDestroy(SL* ps);//打印顺序表voidSLPrint(SL* ps);

3.2 🔔SeqList.c 顺序表的函数定义

#include"SeqList.h"//初始化顺序表voidSLInit(SL* ps){assert(ps);//使用malloc开辟空间 ps->a =(SLDataType*)malloc(sizeof(SLDataType)* SLCAPACITY);//判断空间是否开辟成功if(NULL== ps->a){//打印错误原因(比如 “malloc failed: Out of memory”),方便定位问题;perror("malloc failed");//终止程序并返回非 0 状态码(约定俗成表示程序异常退出),避免后续无效操作。exit(-1);}//初始化顺序表的有效元素个数为 0。 ps->size =0;//记录顺序表当前的最大容量。 ps->capacity = SLCAPACITY;}//销毁顺序表voidSLDestroy(SL* ps){assert(ps);//释放顺序表底层数组占用的动态内存。free(ps->a);//将指针置空,避免 “野指针” 问题。 ps->a =NULL;//重置顺序表的状态变量,让其回归 “初始无效状态”。 ps->size = ps->capacity =0;}//打印顺序表voidSLPrint(SL* ps){assert(ps);for(int i =0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");}

3.3 🔔test.c 顺序表功能测试

#include"SeqList.h"intmain(){ SL sl;//初始化顺序表SLInit(&sl);printf("初始化后的顺序表状态:\n");printf("size = %d, capacity = %d\n", sl.size, sl.capacity);//还没有学习插入操作,在这里手动设置一些数据用于测试打印//不能超过4个,因为我们初始化只申请了四个数据的空间 sl.a[0]=10; sl.a[1]=20; sl.a[2]=30; sl.size =3;//有效数据个数SLPrint(&sl);//销毁顺序表SLDestroy(&sl);return0;}

📝全文总结

本文重点讲解动态顺序表的结构体构建,并实现了初始化打印销毁三大基础操作,明确了每个步骤的核心逻辑与注意事项,为后续学习顺序表的增删查改等进阶操作奠定了坚实基础。

今天的干货分享到这里就结束啦!如果觉得文章还可以的话,希望能给个三连支持一下,聆风吟的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的最大动力!

在这里插入图片描述

Read more

【OpenClaw从入门到精通】第04篇:Web/TUI/钉钉全打通!OpenClaw多端交互实测指南(2026避坑版)

【OpenClaw从入门到精通】第04篇:Web/TUI/钉钉全打通!OpenClaw多端交互实测指南(2026避坑版)

摘要:本文聚焦OpenClaw三大核心交互方式,针对新手“不知如何与AI助理沟通”的痛点,提供Web控制台、TUI终端、聊天软件(以钉钉为核心)的完整实操流程。Web控制台适配电脑端深度配置,TUI终端适合服务器远程维护,聊天软件满足手机端移动办公,三者协同实现“随时随地召唤AI”。文中包含2026实测的命令代码、配置步骤、问题排查方案,所有案例为虚拟构建,代码未上传GitHub,兼顾新手入门与进阶实操,帮助读者快速打通多端交互,最大化OpenClaw使用效率。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】【数字孪生与仿真技术实战指南】 【AI工程化落地与YOLOv8/v9实战】【C#工业上位机高级应用:高并发通信+性能优化】 【Java生产级避坑指南:高并发+性能调优终极实战】【Coze搞钱实战:零代码打造吸金AI助手】

By Ne0inhk
Springboot 4.0十字路口:虚拟线程时代,WebFlux与WebMVC的终极选择

Springboot 4.0十字路口:虚拟线程时代,WebFlux与WebMVC的终极选择

🧑 博主简介:ZEEKLOG博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可关注公众号 “ 心海云图 ” 微信小程序搜索“历代文学”)总架构师,16年工作经验,精通Java编程,高并发设计,分布式系统架构设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。 🤝商务合作:请搜索或扫码关注微信公众号 “ 心海云图 ” Springboot 4.0十字路口:虚拟线程时代,WebFlux与WebMVC的终极选择 当虚拟线程以革命性的姿态降临Java世界,一场关于并发编程范式的静默变革正在发生。Spring开发者站在了选择的十字路口。 2023年,Java 21将虚拟线程从预览特性转为正式功能,这一变化看似只是JVM内部的优化,实则撼动了整个

By Ne0inhk
【鼠鼠优选算法-双指针】001:移动零 & 002:复写零

【鼠鼠优选算法-双指针】001:移动零 & 002:复写零

🎈主页传送门:良木生香 🔥个人专栏:《C语言》 《数据结构-初阶》  🌟人为善,福随未至,祸已远行;人为恶,祸虽未至,福已远离 在学习了这么多基础知识之后,我们就从今天开始操练一下我们的基本技能吧,先来两道简单的题目试试手: 1.移动零:题目链接~~~ 2.复写零:复写零 那我们就一题一题来讲讲吧~~~ 一、移动零 题目描述: 看到题目,这道题是想让我们将一个数组中的所有0移动到数组的末尾. 题目意思明了,但是我们该怎么操作呢? 在这道题中我们第一个想到的就是重新创建新的数组,将数值不为0的元素移动到新的数组中,但是题目明确要求说了,只能再原地进操作,我们该怎么实现这个操作呢?又不能创建新的数组不急,我有妙招. 原理解析: 在这道题目中,我们可以用两个指针,current和dentist,一个用来遍历整个数组,另一个用来处理当下的数据 当cur遍历到值为0的元素时,就与dest交换,随后两者同时向后移动一步 但是不管cur碰到的元素是否等于0,都会向后移动一步   代码实现: 下面是用C语言实现的代码: void Swap(

By Ne0inhk