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

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


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


文章目录

📚专栏订阅推荐

专栏名称专栏简介
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

因AI“认错脸”,50岁的她坐了6个月牢:被当诈骗犯抓走,回来后房子、车子和狗全没了!

因AI“认错脸”,50岁的她坐了6个月牢:被当诈骗犯抓走,回来后房子、车子和狗全没了!

整理 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews) 如果有一天,你只是长得像某个人,就被 AI 认定为罪犯——然后被警方带走、关进监狱半年,你会怎么办? 最近,外媒曝光了一起离谱案件:一位来自美国田纳西州的 50 岁女性,仅仅因为 AI 人脸识别误判,被警方当作银行诈骗案的主犯逮捕,并在监狱里待了将近  6 个月。直到银行流水证明她当时根本不在案发地,检方才撤销全部指控。 然而,当她终于重获自由时,她的生活已经几乎被毁掉——房没了,车没了,甚至连她养的宠物狗也没了。 (Angela Lipps 事后接受媒体采访时的照片) 从没坐过飞机,却被押送 1200 英里受审 如开头所说,这位当事人名叫 Angela Lipps,今年 50 岁,住在美国田纳西州中北部。 她有三个已经成年的孩子,

By Ne0inhk
融资3000万美元,服务2000+团队!听Dify专家拆解如何把AI从Demo变生产力

融资3000万美元,服务2000+团队!听Dify专家拆解如何把AI从Demo变生产力

整理 | 梦依丹      出品 | ZEEKLOG(ID:ZEEKLOGnews) 近日,开源 AI 应用开发平台 Dify 宣布完成 3000 万美元 Pre-A 轮融资,由红杉领投,GL Ventures、Alt-Alpha Capital、五源资本、瑞穗力合投资和 NYX Ventures 跟投,目前公司估值已达 1.8 亿美元。 这家从“原型工具”杀出来的黑马,如今已服务全球超 140 万台设备、2000+ 团队和 280 家企业(包括马士基、安克创新等),正朝着“全球 AI 应用工作流标准定义者”狂奔。 那么,Dify 是如何用“

By Ne0inhk
编写你的第一个 Django 应用(官网demo)

编写你的第一个 Django 应用(官网demo)

安装 Django 确保 Python 已安装(推荐 3.8+版本),通过以下命令安装 Django: pip install django 创建项目 使用 django-admin 创建新项目(例如 djangotutorial): django-admin startproject mysite 目录结构如下: mysite/ manage.py mysite/ __init__.py settings.py urls.py asgi.py wsgi.py 验证: python manage.py runserver 启动开发服务器 进入项目目录并运行: python manage.py runserver 访问

By Ne0inhk
Java 中间件:Kafka 分区策略(自定义分区器实现负载均衡)

Java 中间件:Kafka 分区策略(自定义分区器实现负载均衡)

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕Java中间件这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获! 文章目录 * Java 中间件:Kafka 分区策略(自定义分区器实现负载均衡) 🚀 * 1. Kafka 分区机制基础 🧱 * 1.1 什么是分区? * 1.2 默认分区策略 * 2. 为什么需要自定义分区器?🎯 * 场景一:避免热点分区 🔥 * 场景二:按业务维度分片 🗂️ * 场景三:动态负载感知 📊 * 3. Kafka 分区器接口详解 🛠️ * 核心方法说明: * 4. 实战:实现一个简单的自定义分区器 💻 * 4.1 项目依赖 * 4.2 自定义分区器代码 * 4.3 配置生产者使用自定义分区器

By Ne0inhk