数据结构之旅(顺序表)

embedded/2024/10/17 19:09:25/

前言:  

         Hello,各位小伙伴们我们在过去的60天里学完了C语言基本语法,由于小编在准备数学竞赛,最近没有给大家更新,并且没有及时回复大家的私信,小编在这里和大家说一声对不起!,小编这几天会及时给大家更新初阶数据结构的内容,然后我们来学习今天的内容吧!

一. 顺序表的概念和结构

概念:顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。

结构:顺序表的底层结构式数组,对数组的封装,实现了常用的增删改查等接口。

二.顺序表分类

顺序表分为静态顺序表和动态顺序表:

1>静态顺序表:即数组大小是固定的

...
struct Seqlist
{int arr[1000];//定长数组int size;//有效数组个数
}SL;

2>动态顺序表:即数组大小不是固定的

...
struct Seqlist
{int *arr;int size;//有效数据的个数int capacity;//数组的容量
};

相比于静态顺序表,动态顺序表的优点:既不会因为空间内存不够而造成栈溢出,也不会因为数组容量很大而有效数字较少而造成空间的浪费!

三.动态顺序表的实现

动态顺序表的实现我们分为9个模块,初始化,尾插,头插,尾删,头删,顺序表的查找,插入指定位置的数据,删除指定位置的数据,顺序表的销毁!

在写代码之前我们创建3个文件:一个.h文件,两个.c文件其中的.h文件为seqlist.h用来包含顺序表的框架已经一些函数的声明,其中seqlist.c文件用来实现函数的定义test.c用来不断测试代码的正确性

在进行顺序表实现之前我们首先来对代码简化一下,因为后面要多次使用结构体变量,我们使用typedef来重定义一下.

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
typedef int SLDatatype;
typedef struct SeqList
{SLDatatype* arr;int size;int capacity;
}SL;
//初始化
void SLInit(SL* ps);

1>顺序表的初始化

在.h文件中进行函数的声明,在seqlist.c中进行函数的定义

#include"seqlist.h"
void SLInit(SL* ps)
{ps->arr = NULL;ps->capacity = ps->size = 0;
}

同时小编在这里提醒大家一下在进行初始化的时候记得要进行结构体指针传递,否则只会改变形参而不会改变实参在这里小编给大家演示一下传递结构体值变量的时候:而如果传递的结构体的指变量则会同时改变实参和形参!我们在test.c文件中进行调试一下

我们看到此时实参和形参都发生了变化!

2>顺序表的尾插操作

顺序表的尾插操作大致分为两钟情况:空间足够与空间不够的情况

空间足够的情况下:

在空间足够的情况下,在有效数字的后面直接插入数字即可,可以发现有效数字的个数size做为下标的时候可直接进行插入!

空间不够的情况下:

在空间不够的情况下可以下size和capacity的值相等,要想进行数字的插入需要进行扩容操作!我们使用realloc函数来进行扩容。同时在扩容是要等倍扩容,这样会尽量减少空间的浪费!

void SLPushBack(SL* ps, SLDatatype x)
{assert(ps);//空间不够if (ps->capacity == ps->size){int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDatatype* tmp = (SLDatatype*)realloc(ps->arr, newCapacity *sizeof(SLDatatype));if (tmp == NULL){perror("realloc!");exit(1);}ps->arr = tmp;ps->capacity = newCapacity;}//空间足够ps->arr[ps->size++] = x;
}

 可以看出时间复杂度为O(1)。

同时我们在test.c文件中进行测试:

 3>顺序表的头插操作

我们在进行顺序表的头插操作时,需要先将原来数组的内容整体向后移动一位,然后再将要插入的数据插入到第一个位置中去。同时我们将判断空间大小是否充足代码包装成一个函数

void CheckCapacity(ps)这样就可以使代码简洁。

代码实现:

void SLPushFront(SL* ps, SLDatatype x)
{assert(ps);void CheckCapacity(ps);//判断是否有足够的空间for (int i = ps->size; i > 0; i++){ps->arr[i] = ps->arr[i - 1];}//向后面整体移动一位ps->arr[0] = x;++ps->size;
}

 可以看出时间复杂度为O(n)。

4>顺序表的尾删操作

进行尾删操作时,将有效数字的个数减一,同时在判断有效数字个数不能为0。

void SLPopBack(SL* ps)
{assert(ps&&ps->size);--ps->size;
}

5>顺序表的头删操作

在进行头删操作时,我们只需要将数组内容整体向前移动一位即可!但在移动时我们要注意要从前向后移动。

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

 6>顺序表的查找操作

我们遍历整个数组,找到后返回下标,如果没有找到则返回-1,然后在test.c文件中进行测试

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

测试:

7>在指定位置插入数据

 在指定位置插入数据,我们需要先将该位置之后的数据向后移动一位同时还要判断是否空间足够,然后在该位置插入数据。

void SLInsert(SL* ps, int pos, SLDatatype x)
{                  assert(ps);assert(pos >= 0 && pos <= ps->size);//取等号的时候就是在进行头插与尾插CheckCapacity(ps);for (int i = ps->size;i>pos;i--){ps->arr[i] = ps->arr[i - 1];}++ps->size;ps->arr[pos] = x;
}

测试:

8>删除指定位置的数据

删除指定位置的数据,即将该位置之后的数据向前移动一位,最后不要忘记将有效数据的个数减一。

void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos; i <ps->size; i++){ps->arr[i] = ps->arr[i + 1];}--ps->size;
}

测试:

8>顺序表的销毁

我们在开辟新的空间的时候使用了malloc函数,在使用完成之后要记得将所开辟的空间还给操作系统。

void SLDestory(SL* ps)
{if (ps->arr)free(ps->arr);ps->arr = NULL;ps->capacity = ps->size = 0;
}

测试:

四.完成顺序表所需要注意的事项(总结)

在整体规划部分,动态顺序表的实现过程中我们创建了3个文件与平常不同的是多出来一个test.c测试文件,因为我们要完成许多函数的功能所以创建这个函数目的在于不断测试,在上面我们在书写代码的过程中不断进行函数的测试,同时我们将所有函数的声明都存在了头文件中,在函数定义的文件中我们只需要包含我们创建的这个头文件即可!

在函数实现部分,我们充分考虑到了函数传参问题,将所有可能的情况包含到了其中,尤其传递的指针为空的情况还有值传递于址传递问题。同时将重复的代码部分另外包装成一个新的函数,减少了代码行数。同时在搞不清逻辑关系的时候我们要记得画图!

ok,今天的内容就到这里啦,我们下期再见! 欢迎各位小伙伴在评论区留言。


http://www.ppmy.cn/embedded/126978.html

相关文章

UE5+ChatGPT实现3D AI虚拟人综合实战

第11章 综合实战&#xff1a;UE5ChatGPT实现3D AI虚拟人 通过结合Unreal Engine 5&#xff08;UE5&#xff09;的强大渲染能力和ChatGPT的自然语言处理能力&#xff0c;我们可以实现一个高度交互性的AI虚拟人。本文将详细介绍如何在UE5中安装必要的插件&#xff0c;配置OpenAI…

Fiddler配合wireshark解密ssl

环境&#xff1a; win11&#xff08;wireshark&#xff09;--虚拟机win7&#xff08;Fiddler&#xff09;---虚拟机win7&#xff08;HTTPS站点&#xff09; 软件安装问题&#xff1a; 需要.net环境&#xff0c;NDP461-KB3102436-x86-x64-AllOS-ENU.exe。 安装fiddler后安装下…

自动驾驶 车道检测实用算法

自动驾驶 | 车道检测实用算法 车道识别是自动驾驶领域的一个重要问题&#xff0c;今天介绍一个利用摄像头图像进行车道识别的实用算法。该算法利用了OpenCV库和Udacity自动驾驶汽车数据库的相关内容。 该算法包含以下步骤&#xff1a; 摄像头校准&#xff0c;以移除镜头畸变&…

SldWorks问题 2. 矩阵相关接口使用上的失误

问题 在计算三维点在图纸&#xff08;DrawingDoc&#xff09;中的位置时&#xff0c;就是算不对&#xff0c;明明就4、5行代码&#xff0c;怎么看都是很“哇塞”的&#xff0c;毫无问题的。 但结果就是不对。 那就调试一下吧&#xff0c;调试后发现生成的矩阵很不对劲&#…

C++ 基础

目录 一、命名空间&#xff1b; 1.如何定义&#xff1b; 代码举例&#xff1a; 嵌套定义命名空间&#xff1a; 2.如何使用&#xff1b; &#xff08;1&#xff09;使用加命名空间名称及作用域限定符&#xff1b; 代码举例&#xff1a; 运行结果&#xff1a; &#xff…

MySQL 之慢查询优化

在 MySQL 数据库的使用过程中&#xff0c;慢查询是一个常见的性能问题。慢查询会导致系统响应时间变长&#xff0c;影响用户体验&#xff0c;甚至可能导致系统崩溃。因此&#xff0c;识别和优化慢查询是提高 MySQL 数据库性能的重要任务。 一、识别慢查询 设置慢查询阈值 通过…

(全网独家)面试要懂运维真实案例:HDFS重新平衡(HDFS Balancer)没触发问题排查

在面试时&#xff0c;面试官为了考察面试者是否真的有经验&#xff0c;经常会问运维集群时遇到什么问题&#xff0c;解决具体流程。下面是自己遇到HDFS Balancer没执行&#xff0c;花了半天时间进行排查&#xff0c;全网独家的案例和解决方案。 目录 使用CDH自带重新平衡操作…

路由通信 的 VLAN技术

一、VLAN基础 虚拟局域网&#xff08;Virtual Local Area Network&#xff0c;VLAN&#xff09; 根据管理功能、组织机构或应用类型对交换局域网进行分段而形成的逻辑网络。 交换机最多支持4094个VLAN&#xff0c;其中默认管理VLAN是VLAN1&#xff0c;不能创建&#xff0c;也…