玩转顺序表——【数据结构】

在C语言学习中,我们经常会遇见增删查改等一系列操作,而这些操作全都与线性表关联,没有线性表将会对这些操作完成的十分艰难!那今天就让我们来了解一下顺序表如何增删查改!!!

目录

1.线性表

2.顺序表 

2.1概念及结构

3.对顺序表的实现 

3.1创建动态内容结构体

3.2内存销毁 

 3.3判断是否需要扩容

3.4尾插

3.5头插

3.6 尾删

3.7头删

 3.8 顺序表查找

3.9 顺序表在pos位置插入x

3.10 顺序表删除pos位置的值

顺序表的问题及思考


1.线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储

 

2.顺序表 

2.1概念及结构

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

顺序表一般可以分为:

1. 静态顺序表:使用定长数组存储元素:

 确定的数组是不能改变的

2.动态顺序表:使用动态开辟的数组存储:

通过存放一个结构体指针,使用动态内存开辟malloc函数开辟空间 ,如果空间不够用可以使用realloc函数进行扩容!

3.对顺序表的实现 

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空 间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间 大小,所以下面我们实现动态顺序表。

3.1创建动态内容结构体

typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
  SLDataType* array;  // 指向动态开辟的数组
  size_t size ;       // 有效数据个数
  size_t capicity ;   // 容量空间的大小
}SL;

array是动态内存开辟的数组指针,指向开辟的首元素地址。

size是记录存储有效内容的数据个数,方便统计。

capicity是记录容量大小,方便与size进行比较,用来判断是否需要扩容。

我们使用typedef将int重命名为SLDataType,将结构体命名为SL。

 3.2对结构体进行初始化

//第一种方法
void SeqListInit(SL* ps)
{
	ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);
	if (ps->a == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	ps->size = 0;
	ps->capacity = 4;
}
//第二种方法
void SeqListInit(SL s)
{
	s.a = NULL;
	s.size = 0;
	s.capacity = 0;
}

第二种方法是直接将结构体的内容传给函数,形参只是实参的一份临时拷贝,形参的改变不会影响实参!!!所以第二种方法是错误的!!! 

当我们使用第一种方法初始化时,我们就可以适当的开辟一点空间,如何使用malloc开辟空间在之前的博客中有所讲解http://t.csdn.cn/038La。如果开辟失败我们就直接退出程序exit(-1)。

3.2内存销毁 

在我们使用动态内存开辟后,一定要及时释放空间并置为NULL,否则会出现内存泄漏等大问题!

void SeqListDestroy(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

 3.3判断是否需要扩容

在顺序表的增删查改中,我们时不时需要判断存入的数据是否已满,需不需要扩容。所以我们为了方便使用此功能避免程序冗余,我们可以创建此函数用来判断开辟的内存是否需要扩容。

void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		SLDateType* p = (SLDateType*)realloc(ps->a, sizeof(ps->a) * 2);
		if (*p == NULL)
		{
			perror(realloc);
			exit(-1);
		}
		ps->capacity *= 2;
		ps->a = p;
	}
}

传入结构体指针,判断size与capacity是否相等,如果相等我们就使用realloc函数进行扩容,我们创建新指针指向新创建的空间,开辟比原来大二倍的空间。如果开辟成功我们将更新capacity的值,开辟失败直接退出程序!!!

3.4尾插

void SeqListPushBack(SL* ps, SLDateType x)
{
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

 先使用函数SLCheckCapacity进行判断是否需要进行扩容,在进行尾部插入即可。

3.5头插

将需要的数据在顺序表的头部进行插入,对于顺序表而言效率会非常低,但是我们也必须将其实现。 

void SeqListPushFront(SL* ps, SLDateType x)
{
	SLCheckCapacity(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->a[i] = ps->a[i-1];
	}
	ps->a[0] = x;
	ps->size++;
}

3.6 尾删

尾删非常的简单,我们只需要将数组往前移动一位,size--即可。我们不必担心数据问题,下次再次使用时只需要将内容覆盖即可。

void SeqListPopBack(SL* ps)
{

	assert(ps->size > 0);
	ps->size--;
}

但是在删除时我们得判断顺序表中内容是否为空,防止数组越界。我们使用assert断言函数进行判断即可。

3.7头删

头删与头插的效率都很低下,这也是顺序表的一个大缺点。基本原理与头插差不多,时间复杂度都为O(n),牵一发而动全身。

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

删除时我们必须判断数组是否为空,防止越界。从前向后进行迭代前移进行覆盖,最后将size--即可。

 3.8 顺序表查找

为了让我们方便查找顺序表中每个内容的具体位置,然后插入想插入的数据。我们创建一个寻找下标的函数。

int SeqListFind(SL* ps, SLDateType x)
{
	assert(ps->size > 0);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
			return i;
	}
	else
		return -1;
}

我们使用暴力查找法,将数组遍历一遍,如果能找到则返回其下标,如果找不到则返回-1结束。 

3.9 顺序表在pos位置插入x

我们使用3.8中的函数,将需要插入位置找到,然后使用此函数将其插入到顺序表中。

void SeqListInsert(SL* ps, int pos, SLDateType x)
{
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}

中间插入,前面的数据不需要移动,在pos后的位置要向后移动。

3.10 顺序表删除pos位置的值

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

与插入原理相同,pos后的内容向前一位即可。

顺序表的问题及思考

问题:

1. 中间/头部的插入删除,时间复杂度为O(N)

2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。

3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

思考:如何解决以上问题呢?下面给出了链表的结构来看看。

我们可以使用链表解决以上问题,下一期我们将走进链表章节。

欲知后事如何,尽情期待下一期!!! 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解码“平台工程”,VMware 有备而来

随着全球数字化进程加快&#xff0c;企业使用前沿技术加快商业创新&#xff0c;以提高竞争力。其中如何加快开发效率&#xff0c;为客户创造更多价值成为新的关注焦点。 继DevOps后&#xff0c;“平台工程”&#xff08;Platform Engineering&#xff09; 一词引发热议。平台工…

无涯教程-jQuery - Dialog组件函数

小部件对话框函数可与JqueryUI中的小部件一起使用。对话框是在HTML页面上显示信息的一种不错的方法。对话框是一个带有标题和内容区域的浮动窗口。此窗口可以移动&#xff0c;调整大小&#xff0c;并且默认情况下可以使用" X"图标关闭。 Dialog - 语法 $( "#d…

Qt 4. 发布exe

把ex2.exe放在H盘Ex2文件夹下&#xff0c;执行 H:\Ex2>windeployqt ex2.exe H:\Ex2>windeployqt ex2.exe H:\Ex2\ex2.exe 64 bit, release executable Adding Qt5Svg for qsvgicon.dll Skipping plugin qtvirtualkeyboardplugin.dll due to disabled dependencies (Qt5…

GitHub访问问题与FastGithub下载及使用(详细篇)

目录 FastGithub的介绍 FastGithub的下载 FastGithub的安装及使用 FastGithub的软件功能 FastGithub的部署方式 FastGithub的介绍 FastGithub是一个开源的软件主要为了使GitHub畅通无阻&#xff0c;有超大量的IP资源、快速的IP检测功能&#xff0c;github加速神器&#xf…

android Android Studio Giraffe | 2022.3.1 版本Lombok不兼容 解决方案

android Android Studio Giraffe | 2022.3.1 版本Lombok不兼容 解决方案 1.查看当前的android studio 版本 Android Studio Giraffe | 2022.3.1 Build #AI-223.8836.35.2231.10406996, built on June 29, 2023 2.打开 idea 官网下载页面 idea下载历史版本 找到对应的版本编号…

vue2实现一个树型控件(支持展开树与checkbox勾选)

目录 vue2实现一个树型控件(支持展开树与checkbox勾选)TreeItem.vueTree.vue效果 vue2实现一个树型控件(支持展开树与checkbox勾选) TreeItem.vue <template><div class"tree-item"><span click"toggleExpanded" class"icon" v…

VMware vCenter Server Appliance VCSA 备份还原

vCenter是VMware管理员的常备工具&#xff0c;要保护它的安全&#xff0c;我们可以借助vCenter备份还原方式来达成目的。 怎么备份vCenter 7.0&#xff1f; vCenter备份包括vCenter Server核心配置、资源清册和历史数据&#xff0c;如统计信息、事件和任务。接下来&#xff0…

力扣SQL之路:窗口函数应用

文章目录 1.引言2.力扣SQL题目3. 解题策略4.代码实现5.总结 1.引言 窗口函数是 SQL 中一种强大的分析函数&#xff0c;它可以在结果集中创建一个窗口&#xff0c;并对窗口内的数据进行计算和分析。在力扣&#xff08;LeetCode&#xff09;的 SQL 题目中&#xff0c;窗口函数经…

5分钟快手入门laravel邮件通知

第一步&#xff1a; 生成一个邮件发送对象 php artisan make:mail TestMail 第二步&#xff1a; 编辑.env 添加/修改&#xff08;没有的key则添加&#xff09; MAIL_DRIVERsmtp MAIL_HOSTsmtp.163.com &#xff08;这里用163邮箱&#xff09; MAIL_PORT25 &#xff08;163邮箱…

【LeetCode】160.相交链表

题目 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结…

Istio 安全 授权管理AuthorizationPolicy

这个和cka考试里面的网络策略是类似的。它是可以实现更加细颗粒度限制的。 本质其实就是设置谁可以访问&#xff0c;谁不可以访问。默认命名空间是没有AuthorizationPolicy---允许所有的客户端访问。 这里是没有指定应用到谁上面去&#xff0c;有没有指定使用哪些客户端&#…

细讲TCP三次握手四次挥手(二)

TCP/IP 协议族 应用层 应用层( application-layer &#xff09;的任务是通过应用进程间的交互来完成特定网络应用。应用层协议定义的是应用进程&#xff08;进程&#xff1a;主机中正在运行的程序&#xff09;间的通信和交互的规则。 对于不同的网络应用需要不同的应用层协议…

Keepalived 在CentOS 7安装并配置监听MySQL双主

keepalived安装 MySQL双主配置请看这里&#xff1a;https://tongyao.blog.csdn.net/article/details/132016200?spm1001.2014.3001.5502 128、129两台服务器安装步骤相同&#xff0c;配置文件不同&#xff0c;下面有介绍。 1.安装相关依赖包&#xff0c;并下载keepalived安…

pycharm bash: 第 0 行: cd: xxxxxxx: 没有那个文件或目录

设置里面的python接口&#xff0c;path mappings 是空的&#xff0c;设置好本地机器和远程机器所对应的目录就好了。如下图:

【C++】模板进阶(模板的特化,非类型模板参数,模板的分离编译)

文章目录 一、模板使用时一定要加typename的情况二、 非类型模板参数三、模板的特化1.函数模板特化2.类模板特化1.全特化&#xff1a;2. 偏特化&#xff1a;1. 部分特化2.参数更一步限制 四、模板的分离编译1.Stack.h2.Stack.cpp(定义)3.test.cpp 一、模板使用时一定要加typena…

【虚拟数字人】SadTalker简易部署教程

视频教程在这里&#xff1a; sadtalker数字人创建简易教程 项目基于SadTalkers实现视频唇形合成的Wav2lip。通过以视频文件方式进行语音驱动生成唇形&#xff0c;设置面部区域可配置的增强方式进行合成唇形&#xff08;人脸&#xff09;区域画面增强&#xff0c;提高生成唇形的…

2023年【零声教育】13代C/C++Linux服务器开发高级架构师课程体系分析

对于零声教育的C/CLinux服务器高级架构师的课程到2022目前已经迭代到13代了&#xff0c;像之前小编也总结过&#xff0c;但是课程每期都有做一定的更新&#xff0c;也是为了更好的完善课程跟上目前互联网大厂的岗位技术需求&#xff0c;之前课程里面也包含了一些小的分支&#…

工作记录------单元测试(持续更新)

工作记录------单元测试 之前的工作中从来没有写过单元测试&#xff0c;新入职公司要求写单元测试&#xff0c; 个人觉得&#xff0c;作为程序员单元测试还是必须会写的 于此记录一下首次编写单元测试的过程。 首先引入单元测试相关的依赖 <dependency><groupId>…

【Python目标识别】Labelimg标记深度学习(YOLO)样本

人工智能、ai、深度学习已经火了很长一段时间了&#xff0c;但是还有很多小伙伴没有接触到这个行业&#xff0c;但大家应该多多少少听过&#xff0c;网上有些兼职就是拿电脑拉拉框、数据标注啥的&#xff0c;其实这就是在标记样本&#xff0c;供计算机去学习。所以今天跟大家分…

金融翻译难吗,如何做好金融翻译?

我们知道&#xff0c;金融翻译涉及企业经济这块的&#xff0c;是影响各公司发展很重要的一方面&#xff0c;翻译做得好&#xff0c;可以促进公司内外的交流&#xff0c;及时掌握各种信息&#xff0c;做好应对。那么&#xff0c;金融翻译难吗&#xff0c;如何做好金融翻译&#…