01数据结构 - 顺序表

这里是只讲干货不讲废话的炽念,这个系列的文章是为了我自己以后复习数据结构而写,所以可能会用一种我自己能够听懂的方式来描述,不会像书本上那么枯燥和无聊,且全系列的代码均是可运行的代码,关键地方会给出注释^_^

全文近8000字

版本:C++17

编译器:Clion 2023.3.24

暂时只给出代码,不会涉及到基础知识的讲解

1.线性表的定义

//定义顺序表的表头结构
typedef struct {Element* data;              // 指向顺序表的数据区域int len;                    // 该区域能够访问的边界条件,目前内容器存储数据的数量int cap;                    // 该区域最大容量,超过这个容量就需要扩容
}SeqList;// len 始终指向待插入位置

2.线性表的实现函数

2.1.表的创建以及删除

// 表的创建以及删除
SeqList *createSeqList(int n);                  // 创造一个表并初始化void releaseSeqList(SeqList *seqList);          // 释放掉表头以及表内的数据

 2.2.扩容函数

// 辅助函数
int enLargerSeq(SeqList *seqList);                  // 扩容函数

2.3.向表中插入元素

// 三种插入方式
int pushBackSeq(SeqList *seqList, Element val);         // 往尾部插入一个元素int headInsertSeq(SeqList *seqList, Element val);       // 往头部插入一个元素int insertSeq(SeqList *seqList, int pos, Element val);  // 按指定值来插入元素

2.4.表的展示以及查找

// 展示以及查找
void showSeqList(SeqList *seqList);                // 遍历并显示数据int findSeq(SeqList *seqList, Element val);        // 按值查找

2.5.删除表中的元素

// 三种方式删除
int deleteSpeSeq(SeqList *seqList, Element val);   // 删除特定值的元素int deleteHeadSeq(SeqList *seqList);               // 删除首元素int deleteTailSeq(SeqList *seqList);               // 删除尾元素

3.实现函数的代码

3.1.createSeqList函数的实现

函数定义:
SeqList *createSeqList(int n);                  // 创造一个表并初始化

函数功能:
该函数用于创建一个长度为n的顺序表,并返回指向该顺序表的指针

实现思路
a.申请表头空间b.申请表内元素的空间c.初始化 len(length 长度) 和 cap(capacity 容量)d.对申请的空间进行检查,如果申请空间失败,则需要返回NULL

具体实现代码:
SeqList *createSeqList(int n) {SeqList *seqList;seqList = (SeqList *)malloc(sizeof(SeqList));               //申请表头if (seqList == NULL){printf("Malloc seqlist failed\n");return NULL;}seqList->data = (Element *) malloc(sizeof(Element) * n);    //申请空间if (seqList->data == NULL){printf("Malloc data failed");return NULL;}seqList->len = 0;seqList->cap = n;return seqList;
}

测试代码:
int main() {SeqList *list = createSeqList(10);if (list == NULL) {printf("创建顺序表失败\n");return 1;}printf("顺序表创建成功\n");free(list->data);free(list);return 0;
}

测试结果:

3.2 releaseSeqList函数的实现

函数定义:
void releaseSeqList(SeqList *seqList);          // 释放掉表头以及表内的数据

函数功能:
该函数用于释放一个顺序表所占用的内存空间,防止内存泄漏

实现思路:
a.先判断表头再判断数据域是否为空b.如果数据域不为空,则释放掉表内的数据域空间c.释放掉表头空间

 具体实现代码:
void releaseSeqList(SeqList *seqList) {if (seqList){if (seqList->data){free(seqList->data);}free(seqList);printf("Release success!\n");}
}

测试代码:
int main() {SeqList *list = createSeqList(10);if (list == NULL) {printf("创建顺序表失败\n");return 1;}printf("顺序表创建成功\n");releaseSeqList(list);  // 释放顺序表return 0;
}

测试结果:

3.3 enLargerSeq 函数的实现

函数定义:
int enLargerSeq(SeqList *seqList);                  // 扩容函数

函数功能:
该函数用于对顺序表进行扩容,将顺序表的大小扩展为原来的两倍

实现思路:
a.先申请一个新空间 tmp,新空间的大小为原来空间大小(seqList->len / seqList->cap)的两倍
b.将原来空间的值通过 for 循环赋值给新空间
c.释放掉原来表头指向的空间 seqList->data
d.将表头的 seqList->data 指向新申请的空间 tmp
e.将 seqList->cap 大小变为原来的两倍

具体实现代码:
int enLargerSeq(SeqList *seqList) {Element *tmp = (Element *) malloc(sizeof (Element) * 2 * seqList->cap);if (!tmp){printf("Enlarger element failed!\n");return -1;}for (int i = 0; i < seqList->len; i++){tmp[i] = seqList->data[i];}free(seqList->data);    // 这两句是否有先后?seqList->data = tmp;    // 有先后,如果调换顺序就会先指向新的内存空间,然后再释放老的内存空间,此时老的内存空间已经找不到了,会发生内存泄露seqList->cap *= 2;printf("Enlarge success!\n");return 0;
}

测试代码:
int main(){SeqList *list = createSeqList(5);for (int i = 0; i < 5; i++){pushBackSeq(list, i);}pushBackSeq(list,666);showSeqList(list);printf("%d", list->cap);return 0;
}

测试结果:

3.4 showSeqList && findSeq 函数的实现

函数定义:
void showSeqList(SeqList *seqList);                // 遍历并显示数据int findSeq(SeqList *seqList, Element val);        // 按值查找

函数功能:

1.showSeqList 函数

该函数用于遍历并显示顺序表中的所有数据

2.findSeq 函数 

该函数用于在顺序表中查找指定的值,并返回该值的索引。如果未找到,则返回 -1

实现思路:

1.showSeqList 函数

a.首先判断传入的表是否为空
b.使用 for 循环遍历整个表并打印数据

2.findSeq 函数

a.判断传染的表是否为空且表的长度是否合法(seqList->len > 0)
b.使用for循环遍历表,如果找到了val就直接返回该数的下标
c.如果没找到,打印提示信息,返回-1

具体实现代码:
// showSeqList 函数
void showSeqList(SeqList *seqList) {if (seqList == NULL || seqList->data == NULL){printf("SeqList is null.Show error\n");return;}for (int i = 0; i < seqList->len; i++){printf("%d ", seqList->data[i]);}printf("\n");
}// findSeq 函数
int findSeq(SeqList *seqList, Element val) {if (!seqList || !seqList->data || seqList->len <= 0){printf("SeqList is null!\n");return -1;}for (int i = 0; i < seqList->len; i++){if (seqList->data[i] == val){return i;}}printf("Find value error!\n");return -1;
}

测试代码:
int main(){SeqList *list = createSeqList(5);for (int i = 0; i < 5; i++){pushBackSeq(list, i);}showSeqList(list);int index1 = findSeq(list, 666);int index2 = findSeq(list,0);printf("%d\n", index1);printf("%d\n", index2);releaseSeqList(list);return 0;
}

测试结果:

3.4 pushBackSeq && headInsertSeq && insertSeq 函数的实现

函数定义:
int pushBackSeq(SeqList *seqList, Element val);         // 往尾部插入一个元素int headInsertSeq(SeqList *seqList, Element val);       // 往头部插入一个元素int insertSeq(SeqList *seqList, int pos, Element val);  // 按指定位置来插入元素

函数功能:
1.pushBackSeq 函数
在顺序表尾部插入一个元素
2.headInsertSeq 函数
在顺序表头部插入一个元素
3.insertSeq 函数
在顺序表指定位置插入一个元素

实现思路:

1.pushBackSeq 函数

a.判断传入的链表以及数据域是否为空b.判断当前元素是否到达空间上限,如果是则需要扩容c.往 seqList->len 的位置放入元素d.seqList->len++

 2.headInsertSeq 函数

a.判断传入的链表以及数据域是否为空b.判断当前元素是否到达空间上限,如果是则需要扩容c.从第 1 个元素开始,依次往后移动元素d.往下标为 0 的位置放入元素e.seqList->len++

3.insertSeq 函数

a.判断传入的链表以及数据域是否为空b.判断当前元素是否到达空间上限,如果是则需要扩容c.从第 seqList->len-1 个元素开始,直到第 pos 个元素(包含),从后往前移动元素d.往下标为 pos 的位置放入元素e.seqList->len++

具体实现代码:

1.pushBackSeq 函数

// pushBackSeq 函数
int pushBackSeq(SeqList *seqList, Element val) {if (!seqList || !seqList->data){printf("Seqlist is null");return -1;}if (seqList->len >= seqList->cap){printf("Insertion overflow. Consider enlarging the structure!\n");if (enLargerSeq(seqList) == -1){printf("Enlarge failed!\n");return -1;}}seqList->data[seqList->len] = val;seqList->len++;return 0;
}

  2.headInsertSeq 函数

// headInsertSeq 函数
int headInsertSeq(SeqList *seqList, Element val) {if (!seqList || !seqList->data){printf("Seqlist is null");return -1;}if (seqList->len >= seqList->cap){printf("Insertion overflow. Consider enlarging the structure!\n");if (enLargerSeq(seqList) == -1){printf("Enlarge failed!\n");return -1;}}for (int i = seqList->len; i > 0; i--) {        // 核心移动逻辑seqList->data[i] = seqList->data[i-1];}seqList->data[0] = val;seqList->len++;return 0;
}

 3.insertSeq 函数

// insertSeq 函数
int insertSeq(SeqList *seqList, int pos, Element val) {if (!seqList || !seqList->data){printf("Seqlist is null");return -1;}// 为什么是 > seqList->len,而不是 > seqList->cap?// 顺序表是一种线性数据结构,它要求元素在内存中连续存储。这意味着元素之间不能有空隙,必须紧密排列// 使用 len 而不是 cap 来确定插入位置,可以保证顺序表中的元素始终保持连续存储,这是顺序表的核心特征if (pos < 0 || pos > seqList->len){printf("Insert value out of bounds\n");return -1;}if (seqList->len >= seqList->cap){printf("Insertion overflow. Consider enlarging the structure!\n");if (enLargerSeq(seqList) == -1){printf("Enlarge failed!\n");return -1;}}for (int i = seqList->len-1; i >= pos; i--){    // 核心移动逻辑seqList->data[i+1] = seqList->data[i];}seqList->data[pos] = val;seqList->len++;return 0;
}

测试代码:
int main(){SeqList *list = createSeqList(5);for (int i = 0; i < 5; i++){pushBackSeq(list, i);}showSeqList(list);insertSeq(list, 5, 111);      // 任意位置插入showSeqList(list);insertSeq(list, 0, 222);      // 任意位置插入showSeqList(list);insertSeq(list, 999, 333);    // 任意位置插入showSeqList(list);printf("\n");headInsertSeq(list, 888);     // 头插法showSeqList(list);printf("\n");pushBackSeq(list, 666);       // 尾插法showSeqList(list);releaseSeqList(list);return 0;
}

测试结果:

3.5 deleteSpeSeq && deleteHeadSeq && deleteTailSeq 函数的实现

函数定义:
int deleteSpeSeq(SeqList *seqList, Element val);   // 删除特定值的元素int deleteHeadSeq(SeqList *seqList);               // 删除首元素int deleteTailSeq(SeqList *seqList);               // 删除尾元素

函数功能:

1.deleteSpeSeq 函数

该函数用于在顺序表中删除指定值的元素

2. deleteHeadSeq 函数  

该函数用于删除顺序表中的首元素

 3.deleteTailSeq 函数 

该函数用于删除顺序表中的尾元素

实现思路:

1.deleteSpeSeq 函数

a.判断传入的表是否为空
b.调用 findSeq 函数,判断要查找的值是否在表中
c.如果不在表中,则返回错误标志
d.从 pos+1 的位置开始,从后往前覆盖元素
e.seqList->len--

2. deleteHeadSeq 函数 

a.判断传入的表是否为空
b.判断表内是否有元素
c.从第二个元素(索引为1)开始,从后往前进行覆盖
d.seqList->len--

3.deleteTailSeq 函数 

a.判断传入的表是否为空
b.判断表内是否有元素
d.seqList->len--

具体实现代码:

1.deleteSpeSeq 函数

int deleteSpeSeq(SeqList *seqList, Element val) {if (!seqList || !seqList->data){printf("Seqlist is null. Delete failed!\n");return -1;}int pos = findSeq(seqList, val);if (pos == -1){printf("Delete value error!\n");return -1;}for (int i = pos + 1; i < seqList->len; i++){seqList->data[i - 1] = seqList->data[i];}/*for (int i = pos; i < seqList->len; i++){ // 第二种写法可能会有溢出的风险seqList->data[i] = seqList->data[i + 1];}*/seqList->len--;return 0;
}

2. deleteHeadSeq 函数

int deleteHeadSeq(SeqList *seqList) {if (!seqList || !seqList->data){printf("Seqlist is null. Delete failed!\n");return -1;}if (seqList->len <= 0){printf("Delete head value failed!");return -1;}for (int i = 1; i < seqList->len; i++){seqList->data[i-1] = seqList->data[i];}seqList->len--;return 0;
}

3.deleteTailSeq 函数

int deleteTailSeq(SeqList *seqList) {if (!seqList || !seqList->data){printf("Seqlist is null. Delete failed!\n");return -1;}if (seqList->len <= 0){printf("Delete tail value failed!");return -1;}seqList->len--;return 0;
}

测试代码:
int main(){SeqList *list = createSeqList(5);for (int i = 0; i < 5; i++){pushBackSeq(list, i);}deleteHeadSeq(list);showSeqList(list);deleteTailSeq(list);showSeqList(list);deleteSpeSeq(list,999);showSeqList(list);deleteSpeSeq(list,1);showSeqList(list);releaseSeqList(list);return 0;
}

测试结果:

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

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

相关文章

C++客户端Qt开发——常用控件(容器类控件)

6.容器类控件 ①GroupBox 带标题分组框 属性 说明 title 分组框的标题 alignment 分组框内部内容的对齐方式 flat 是否是"扁平"模式 checkable 是否可选择 设为true,则在title前方会多出一个可勾选的部分. check 描述分组框的选择状态&#xff08;前提…

数据结构(5.1)——树的性质

结点数总度数1 结点的度——结点有几个孩子(分支) 度为m的树、m叉树的区别 度为m的树第i层至多有 个结点(i>1) 高度为h的m叉树至多有 个结点 高度为h的m叉树至少有h个结点 、高度为h&#xff0c;度为m叉树至多有hm-1个结点 具有n个结点的m叉树的最小高度为 总结

通过角点进行水果的果梗检测一种新方法

一、前言 在前面的《数字图像处理与机器视觉》案例一&#xff08;库尔勒香梨果梗提取和测量&#xff09;中主要使用数学形态学的方法进行果梗提取&#xff0c;下面给出一种提取果梗的新思路。 众所周知&#xff0c;一般果梗和果实在边缘处角度有较大突变&#xff0c;可以通过合…

spring security源码追踪理解(一)

一、前言 近期看了spring security相关的介绍&#xff0c;再加上项目所用若依框架的底层安全模块也是spring security&#xff0c;所以想从源码的角度加深下对该安全模块的理解&#xff08;看源码之前&#xff0c;我们要先有个意识&#xff0c;那就是spring security安全模块主…

第122天:内网安全-域信息收集应用网络凭据CS 插件AdfindBloodHound

目录 前置知识 背景和思路 判断是否在域内 案例一&#xff1a;架构信息类收集-网络&用户&域控等 案例二&#xff1a;自动化工具探针-插件&Adfind&BloodHound Adfind(域信息收集工具) ​BloodHound&#xff08;自动化域渗透工具&#xff09; 前置知识 本…

搭建个人智能家居 7 - 空气颗粒物检测

搭建个人智能家居 7 - 空气颗粒物检测 前言说明PMS5003ESPHomeHomeAssistant结束 前言 到目前为止&#xff0c;我们这个智能家居系统添加了4个外设&#xff0c;分别是&#xff1a;LED灯、RGB灯、DHT11温度传感器和SGP30。今天继续添加环境测量类传感器“PMS5003空气颗粒物检测…

Windows FFmpeg 开发环境搭建

FFmpeg 开发环境搭建 FFmpeg命令行环境搭建使用FFmpeg官方编译的库Windows编译FFmpeg1. 下载[msys2](https://www.msys2.org/#installation)2. 安装完成之后,将安装⽬录下的msys2_shell.cmd中注释掉的 rem set3. 修改pacman 镜像源并安装依赖4. 下载并编译源码 FFmpeg命令行环境…

基于springboot和mybatis的RealWorld后端项目实战三之添加swagger

pom.xml添加依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>io.springfox</groupId><arti…

解决网页中的 video 标签在移动端浏览器(如百度访问网页)视频脱离文档流播放问题

问题现象 部分浏览器视频脱离文档流&#xff0c;滚动时&#xff0c;视频是悬浮出来&#xff0c;在顶部播放 解决方案 添加下列属性&#xff0c;可解决大部分浏览器的脱离文档流的问题 <videowebkit-playsinline""playsInlinex5-playsinlinet7-video-player-t…

AI辅助自动驾驶技术在2024年的发展与趋势

文章目录 综述 2024 年 AI 辅助研发趋势 第一章&#xff1a;引言 1.1 背景介绍 1.2 AI在自动驾驶中的地位和作用 1.3 2024年自动驾驶技术的现状 1.4 论文结构 第二章&#xff1a;AI技术在自动驾驶中的应用 2.1 深度学习算法在自动驾驶中的应用 2.2 数据分析与模式识别…

谷类大米农业行业网站源码系统 带完整的安装代码包以及搭建部署教程

系统概述 在当今数字化时代&#xff0c;农业行业也逐渐迈向信息化、智能化。为了满足谷类大米农业行业的信息化需求&#xff0c;我们推出了一款专为该行业设计的网站源码系统。该系统不仅具备丰富的行业特色功能&#xff0c;而且提供了完整的安装代码包以及详细的搭建部署教程…

【Java算法】前缀和 下

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【算法工作坊】算法实战揭秘 一.连续数组 题目链接&#xff1a;525.连续数组 代码 public int findMaxLength(int[] nums) {HashMap<Integer,Integer> mapnew HashMap<>();map.put(0,-1);…

Camera Raw:移去

Camera Raw 中的移去 Remove模块主要用于去除照片中的不需要的元素&#xff0c;比如污点、电线或其它干扰元素。 快捷键&#xff1a;B 移去面板中提供了三种移去模式&#xff1a;移除、修复以及仿制。 移除 Remove 通过智能算法和生成式 AI 来去除不需要的元素。 对象识别 Obje…

php 小白新手从入门到精通教程(第3版)

前言 PHP&#xff08;PHP: Hypertext Preprocessor&#xff09;即“超文本预处理器”&#xff0c;是在服务器端执行的脚本语言&#xff0c;尤其适用于Web开发并可嵌入HTML中。PHP语法学习了C语言&#xff0c;吸纳Java和Perl多个语言的特色发展出自己的特色语法&#xff0c;并根…

FastAPI 学习之路(五十二)WebSockets(八)接受/发送json格式消息

前面我们发送的大多数都是text类型的消息&#xff0c;对于text消息来说&#xff0c;后端处理出来要麻烦的多&#xff0c;那么我们可以不可以传递json格式的数据&#xff0c;对于前后端来说都比较友好&#xff0c;答案是肯定的&#xff0c;我们需要做下处理。 首先&#xff0c;…

云计算安全流程与管控要求的全面解析

华为云安全流程与管控要求的全面解析 引言 在云计算技术迅猛发展的背景下&#xff0c;云安全问题日益凸显其重要性。华为云作为行业的领军企业&#xff0c;其安全流程与管控要求不仅关乎自身的服务稳定性&#xff0c;更直接影响到广大用户的业务安全。本文将深入解析华为云的安…

InterSystems IRIS使用python pyodbc连接 linux环境,odbc驱动安装,DSN配置,数据源配置,linux中文不展示问题

1、官方文档 ODBC Installation and Validation on UNIX Systems | Using the InterSystems ODBC Driver | InterSystems IRIS for Health 2024.1 By default, a full ODBC installation is performed with a standard InterSystems installation. If you perform a custom i…

beego框架_golang web框架_使用介绍

beego简介 beego是一个用于快速开发Go应用的http框架&#xff0c;由Go语言方面的技术大牛设计。beego可以用来快速开发API、Web、后端服务等各种应用&#xff0c;是一个RESTful的框架&#xff0c;主要设计灵感来源于tornado、sinatra、flask这三个框架&#xff0c;但结合了Go本…

《Windows API每日一练》10.3 公用对话框

Windows最初发行时的主要目标之一就是提倡一种标准化的用户界面。对于公用菜单 项来说&#xff0c;这一目标实现得很快。几乎所有的软件制造商都采用了Alt-File-Open组合来打开 文件。但是&#xff0c;真正用来打开文件的对话框却经常很不一样。 从Windows 3.1开始&#xff0c…

【JVM基础02】——组成-程序计数器解读

目录 1- 引言&#xff1a;程序计数器1-1 程序计数器是什么&#xff1f;为什么用程序计数器&#xff1f;(What)(Why) 2- 核心&#xff1a;程序计数器的原理&#xff08;How&#xff09;2-1 使用 javap 查看程序计数器的作用2-2 多线程下程序计数器原理举例 3- 小结&#xff1a;什…